iSulad/0003-Modified-the-procedure-of-running-a-pod-to-adapt-to-.patch

1396 lines
53 KiB
Diff
Raw Normal View History

From 1b3922edcd0c254b39d57d91b9e027069cd8c82f Mon Sep 17 00:00:00 2001
From: chengzrz <czrzrichard@gmail.com>
Date: Mon, 22 Nov 2021 15:34:04 +0800
Subject: [PATCH 03/14] Modified the procedure of running a pod to adapt to
kata 2.0
Signed-off-by: chengzrz <czrzrichard@gmail.com>
---
src/common/constants.h | 2 +
src/daemon/entry/cri/cni_network_plugin.cc | 33 ++++-
src/daemon/entry/cri/cri_constants.cc | 1 +
src/daemon/entry/cri/cri_constants.h | 1 +
src/daemon/entry/cri/cri_helpers.cc | 1 +
src/daemon/entry/cri/cri_helpers.h | 1 +
.../cri_pod_sandbox_manager_service_impl.cc | 128 +++++++++++-----
.../cri_pod_sandbox_manager_service_impl.h | 2 +-
src/daemon/entry/cri/cri_security_context.cc | 3 +
.../executor/container_cb/execution_create.c | 65 +++++++++
.../executor/container_cb/execution_network.c | 3 +-
.../executor/container_cb/execution_network.h | 1 -
.../modules/api/network_namespace_api.h | 35 +++++
src/daemon/modules/api/specs_api.h | 4 +-
src/daemon/modules/container/container_unix.c | 1 +
.../modules/service/inspect_container.c | 35 +++++
.../modules/service/network_namespace_api.c | 80 ++++++++++
.../modules/service/service_container.c | 15 +-
src/daemon/modules/spec/specs.c | 64 ++++++--
src/daemon/modules/spec/specs_namespace.c | 86 ++++++++++-
src/daemon/modules/spec/specs_namespace.h | 5 +
src/utils/cutils/namespace.h | 18 +++
src/utils/cutils/utils_file.c | 23 +++
src/utils/cutils/utils_file.h | 2 +
src/utils/cutils/utils_network.c | 138 ++++++++++++++++++
src/utils/cutils/utils_network.h | 33 +++++
26 files changed, 713 insertions(+), 67 deletions(-)
create mode 100644 src/daemon/modules/api/network_namespace_api.h
create mode 100644 src/daemon/modules/service/network_namespace_api.c
create mode 100644 src/utils/cutils/utils_network.c
create mode 100644 src/utils/cutils/utils_network.h
diff --git a/src/common/constants.h b/src/common/constants.h
index 94640fa5..cb6ce189 100644
--- a/src/common/constants.h
+++ b/src/common/constants.h
@@ -129,6 +129,8 @@ extern "C" {
#define EVENT_ARGS_MAX 255
#define EVENT_EXTRA_ANNOTATION_MAX 255
+#define NETNS_LEN 16
+
/* container id max length */
#define CONTAINER_ID_MAX_LEN 64
diff --git a/src/daemon/entry/cri/cni_network_plugin.cc b/src/daemon/entry/cri/cni_network_plugin.cc
index 35273c3e..ffdbeb10 100644
--- a/src/daemon/entry/cri/cni_network_plugin.cc
+++ b/src/daemon/entry/cri/cni_network_plugin.cc
@@ -28,6 +28,7 @@
#include "utils.h"
#include "errors.h"
#include "service_container_api.h"
+#include "network_namespace_api.h"
namespace Network {
static auto GetLoNetwork(std::vector<std::string> binDirs) -> std::unique_ptr<CNINetwork>
@@ -486,9 +487,15 @@ void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name,
if (err.NotEmpty()) {
return;
}
- std::string netnsPath = GetNetNS(id, err);
- if (err.NotEmpty()) {
- ERROR("CNI failed to retrieve network namespace path: %s", err.GetCMessage());
+
+ auto iter = annotations.find(CRIHelpers::Constants::POD_SANDBOX_KEY);
+ if (iter == annotations.end()) {
+ ERROR("Failed to find sandbox key from annotations");
+ return;
+ }
+ const std::string netnsPath = iter->second;
+ if (netnsPath.length() == 0) {
+ ERROR("Failed to get network namespace path");
return;
}
@@ -517,7 +524,6 @@ void CniNetworkPlugin::SetUpPod(const std::string &ns, const std::string &name,
err.AppendError(tmpErr.GetMessage());
}
}
-
UnlockNetworkMap(err);
}
@@ -593,10 +599,21 @@ void CniNetworkPlugin::TearDownPod(const std::string &ns, const std::string &nam
}
Errors tmpErr;
- std::string netnsPath = GetNetNS(id, err);
- if (err.NotEmpty()) {
- WARN("CNI failed to retrieve network namespace path: %s", err.GetCMessage());
- err.Clear();
+ auto iter = annotations.find(CRIHelpers::Constants::POD_SANDBOX_KEY);
+ if (iter == annotations.end()) {
+ ERROR("Failed to find sandbox key from annotations");
+ return;
+ }
+ std::string netnsPath = iter->second;
+ if (netnsPath.length() == 0) {
+ ERROR("Failed to get network namespace path");
+ return;
+ }
+
+ // When netns file does not exist, netnsPath is assigned to an
+ // empty string so that lxc can handle the path properly
+ if (!util_file_exists(netnsPath.c_str())) {
+ netnsPath = "";
}
RLockNetworkMap(err);
diff --git a/src/daemon/entry/cri/cri_constants.cc b/src/daemon/entry/cri/cri_constants.cc
index b557d56a..265e38e5 100644
--- a/src/daemon/entry/cri/cri_constants.cc
+++ b/src/daemon/entry/cri/cri_constants.cc
@@ -16,6 +16,7 @@
namespace CRI {
const std::string Constants::namespaceModeHost { "host" };
+const std::string Constants::namespaceModeFile { "file" };
const std::string Constants::nameDelimiter { "_" };
const std::string Constants::kubePrefix { "k8s" };
const std::string Constants::sandboxContainerName { "POD" };
diff --git a/src/daemon/entry/cri/cri_constants.h b/src/daemon/entry/cri/cri_constants.h
index 4e964714..95b82660 100644
--- a/src/daemon/entry/cri/cri_constants.h
+++ b/src/daemon/entry/cri/cri_constants.h
@@ -20,6 +20,7 @@ namespace CRI {
class Constants {
public:
const static std::string namespaceModeHost;
+ const static std::string namespaceModeFile;
// sandboxname default values
const static std::string nameDelimiter;
constexpr static char nameDelimiterChar { '_' };
diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc
index f45c669f..525d65a0 100644
--- a/src/daemon/entry/cri/cri_helpers.cc
+++ b/src/daemon/entry/cri/cri_helpers.cc
@@ -42,6 +42,7 @@ const std::string Constants::CONTAINER_TYPE_LABEL_CONTAINER { "container" };
const std::string Constants::CONTAINER_LOGPATH_LABEL_KEY { "cri.container.logpath" };
const std::string Constants::CONTAINER_HUGETLB_ANNOTATION_KEY { "cri.container.hugetlblimit" };
const std::string Constants::SANDBOX_ID_LABEL_KEY { "cri.sandbox.id" };
+const std::string Constants::POD_SANDBOX_KEY { "sandboxkey" };
const std::string Constants::KUBERNETES_CONTAINER_NAME_LABEL { "io.kubernetes.container.name" };
const std::string Constants::POD_INFRA_CONTAINER_NAME { "POD" };
const std::string Constants::DOCKER_IMAGEID_PREFIX { "docker://" };
diff --git a/src/daemon/entry/cri/cri_helpers.h b/src/daemon/entry/cri/cri_helpers.h
index 9eccc1da..5c2f6517 100644
--- a/src/daemon/entry/cri/cri_helpers.h
+++ b/src/daemon/entry/cri/cri_helpers.h
@@ -39,6 +39,7 @@ public:
static const std::string CONTAINER_LOGPATH_LABEL_KEY;
static const std::string CONTAINER_HUGETLB_ANNOTATION_KEY;
static const std::string SANDBOX_ID_LABEL_KEY;
+ static const std::string POD_SANDBOX_KEY;
static const std::string KUBERNETES_CONTAINER_NAME_LABEL;
static const std::string POD_INFRA_CONTAINER_NAME;
// DOCKER_IMAGEID_PREFIX is the prefix of image id in container status.
diff --git a/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc b/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc
index 0f9ef044..eb1cd09f 100644
--- a/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc
+++ b/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc
@@ -13,6 +13,8 @@
* Description: provide cri pod sandbox manager service implementation
*********************************************************************************/
#include "cri_pod_sandbox_manager_service_impl.h"
+
+#include <sys/mount.h>
#include "isula_libutils/log.h"
#include "isula_libutils/host_config.h"
#include "isula_libutils/container_config.h"
@@ -24,7 +26,11 @@
#include "naming.h"
#include "service_container_api.h"
#include "cxxutils.h"
+#include "network_namespace_api.h"
#include "cri_image_manager_service_impl.h"
+#include "utils_network.h"
+#include "namespace.h"
+#include "constants.h"
namespace CRI {
auto PodSandboxManagerServiceImpl::EnsureSandboxImageExists(const std::string &image, Errors &error) -> bool
@@ -49,7 +55,8 @@ auto PodSandboxManagerServiceImpl::EnsureSandboxImageExists(const std::string &i
}
void PodSandboxManagerServiceImpl::ApplySandboxLinuxOptions(const runtime::v1alpha2::LinuxPodSandboxConfig &lc,
- host_config *hc, container_config *custom_config, Errors &error)
+ host_config *hc, container_config *custom_config,
+ Errors &error)
{
CRISecurity::ApplySandboxSecurityContext(lc, custom_config, hc, error);
if (error.NotEmpty()) {
@@ -279,8 +286,8 @@ error_out:
}
container_create_request *PodSandboxManagerServiceImpl::GenerateSandboxCreateContainerRequest(
- const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image,
- std::string &jsonCheckpoint, const std::string &runtimeHandler, Errors &error)
+ const runtime::v1alpha2::PodSandboxConfig &config, const std::string &image, std::string &jsonCheckpoint,
+ const std::string &runtimeHandler, Errors &error)
{
container_create_request *create_request = nullptr;
host_config *hostconfig = nullptr;
@@ -338,7 +345,8 @@ cleanup:
auto PodSandboxManagerServiceImpl::CreateSandboxContainer(const runtime::v1alpha2::PodSandboxConfig &config,
const std::string &image, std::string &jsonCheckpoint,
- const std::string &runtimeHandler, Errors &error) -> std::string
+ const std::string &runtimeHandler, Errors &error)
+-> std::string
{
std::string response_id;
container_create_request *create_request =
@@ -464,16 +472,12 @@ cleanup:
}
void PodSandboxManagerServiceImpl::SetupSandboxNetwork(const runtime::v1alpha2::PodSandboxConfig &config,
- const std::string &response_id, const std::string &jsonCheckpoint,
- Errors &error)
+ const std::string &response_id,
+ const std::string &jsonCheckpoint, const container_inspect *inspect_data, Errors &error)
{
std::map<std::string, std::string> stdAnnos;
std::map<std::string, std::string> networkOptions;
-
- container_inspect *inspect_data = CRIHelpers::InspectContainer(response_id, error, false);
- if (error.NotEmpty()) {
- return;
- }
+ const char* sandbox_key = get_sandbox_key(inspect_data);
// Setup sandbox files
if (config.has_dns_config() && inspect_data->resolv_conf_path != nullptr) {
@@ -493,7 +497,10 @@ void PodSandboxManagerServiceImpl::SetupSandboxNetwork(const runtime::v1alpha2::
CRIHelpers::ProtobufAnnoMapToStd(config.annotations(), stdAnnos);
stdAnnos[CRIHelpers::Constants::POD_CHECKPOINT_KEY] = jsonCheckpoint;
networkOptions["UID"] = config.metadata().uid();
-
+ if (sandbox_key == NULL) {
+ goto cleanup;
+ }
+ stdAnnos.insert(std::pair<std::string, std::string>(CRIHelpers::Constants::POD_SANDBOX_KEY, sandbox_key));
m_pluginManager->SetUpPod(config.metadata().namespace_(), config.metadata().name(),
Network::DEFAULT_NETWORK_INTERFACE_NAME, response_id, stdAnnos, networkOptions, error);
if (error.NotEmpty()) {
@@ -503,15 +510,16 @@ void PodSandboxManagerServiceImpl::SetupSandboxNetwork(const runtime::v1alpha2::
}
cleanup:
- free_container_inspect(inspect_data);
+ return;
}
-
auto PodSandboxManagerServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSandboxConfig &config,
const std::string &runtimeHandler, Errors &error) -> std::string
{
std::string response_id;
std::string jsonCheckpoint;
+ container_inspect *inspect_data = nullptr;
+ char *netnsPath = nullptr;
if (m_cb == nullptr || m_cb->container.create == nullptr || m_cb->container.start == nullptr) {
error.SetError("Unimplemented callback");
@@ -539,13 +547,33 @@ auto PodSandboxManagerServiceImpl::RunPodSandbox(const runtime::v1alpha2::PodSan
error.Clear();
}
- // Step 4: Start the sandbox container.
- StartSandboxContainer(response_id, error);
+ // Step 4: mount network namespace when network mode is file
+ inspect_data = CRIHelpers::InspectContainer(response_id, error, true);
if (error.NotEmpty()) {
goto cleanup;
}
+ if (inspect_data == nullptr || inspect_data->host_config == nullptr) {
+ error.Errorf("Failed to retrieve inspect data");
+ ERROR("Failed to retrieve inspect data");
+ goto cleanup;
+ }
+ netnsPath = get_sandbox_key(inspect_data);
+ if (namespace_is_file(inspect_data->host_config->network_mode)) {
+ if (!util_file_exists(netnsPath) || util_mount_namespace(netnsPath) != 0) {
+ error.Errorf("Failed to mount network namespace");
+ ERROR("Failed to mount network namespace");
+ goto cleanup;
+ }
+ }
+
// Step 5: Setup networking for the sandbox.
- SetupSandboxNetwork(config, response_id, jsonCheckpoint, error);
+ SetupSandboxNetwork(config, response_id, jsonCheckpoint, inspect_data, error);
+ if (error.NotEmpty()) {
+ goto cleanup;
+ }
+
+ // Step 6: Start the sandbox container.
+ StartSandboxContainer(response_id, error);
if (error.NotEmpty()) {
goto cleanup;
}
@@ -555,13 +583,21 @@ cleanup:
SetNetworkReady(response_id, true, error);
DEBUG("set %s ready", response_id.c_str());
error.Clear();
+ } else {
+ if (netnsPath != nullptr && remove_network_namespace(netnsPath) != 0) {
+ ERROR("Failed to remove network namespace");
+ }
}
+ free_container_inspect(inspect_data);
+ free(netnsPath);
return response_id;
}
auto PodSandboxManagerServiceImpl::GetRealSandboxIDToStop(const std::string &podSandboxID, bool &hostNetwork,
- std::string &name, std::string &ns, std::string &realSandboxID,
- std::map<std::string, std::string> &stdAnnos, Errors &error) -> int
+ std::string &name, std::string &ns,
+ std::string &realSandboxID,
+ std::map<std::string, std::string> &stdAnnos, Errors &error)
+-> int
{
Errors statusErr;
@@ -670,16 +706,32 @@ auto PodSandboxManagerServiceImpl::GetNetworkReady(const std::string &podSandbox
}
auto PodSandboxManagerServiceImpl::ClearCniNetwork(const std::string &realSandboxID, bool hostNetwork,
- const std::string &ns,
- const std::string &name, std::vector<std::string> &errlist,
+ const std::string &ns, const std::string &name,
+ std::vector<std::string> &errlist,
std::map<std::string, std::string> &stdAnnos, Errors &
/*error*/) -> int
{
Errors networkErr;
+ container_inspect* inspect_data = nullptr;
bool ready = GetNetworkReady(realSandboxID, networkErr);
if (!hostNetwork && (ready || networkErr.NotEmpty())) {
Errors pluginErr;
+
+ // hostNetwork has indicated network mode which render host config unnecessary
+ // so that with_host_config is set to be false.
+ inspect_data = CRIHelpers::InspectContainer(realSandboxID, pluginErr, false);
+ if (pluginErr.NotEmpty()) {
+ ERROR("Failed to inspect container");
+ }
+
+ char* netnsPath = get_sandbox_key(inspect_data);
+ if (netnsPath == nullptr) {
+ ERROR("Failed to get network namespace path");
+ return 0;
+ }
+
+ stdAnnos.insert(std::pair<std::string, std::string>(CRIHelpers::Constants::POD_SANDBOX_KEY, netnsPath));
m_pluginManager->TearDownPod(ns, name, Network::DEFAULT_NETWORK_INTERFACE_NAME, realSandboxID, stdAnnos,
pluginErr);
if (pluginErr.NotEmpty()) {
@@ -691,8 +743,13 @@ auto PodSandboxManagerServiceImpl::ClearCniNetwork(const std::string &realSandbo
if (pluginErr.NotEmpty()) {
WARN("set network ready: %s", pluginErr.GetCMessage());
}
+ // umount netns when cni removed network successfully
+ if (util_umount_namespace(netnsPath) != 0) {
+ ERROR("Failed to umount directory %s:%s", netnsPath, strerror(errno));
+ }
}
}
+ free_container_inspect(inspect_data);
return 0;
}
@@ -806,7 +863,6 @@ void PodSandboxManagerServiceImpl::ClearNetworkReady(const std::string &podSandb
}
}
-
int PodSandboxManagerServiceImpl::DoRemovePodSandbox(const std::string &realSandboxID, std::vector<std::string> &errors)
{
int ret = 0;
@@ -878,8 +934,8 @@ cleanup:
error.SetAggregate(errors);
}
-auto PodSandboxManagerServiceImpl::SharesHostNetwork(const container_inspect *inspect) ->
-runtime::v1alpha2::NamespaceMode
+auto PodSandboxManagerServiceImpl::SharesHostNetwork(const container_inspect *inspect)
+-> runtime::v1alpha2::NamespaceMode
{
if (inspect != nullptr && inspect->host_config != nullptr && (inspect->host_config->network_mode != nullptr) &&
std::string(inspect->host_config->network_mode) == CRI::Constants::namespaceModeHost) {
@@ -1032,10 +1088,9 @@ void PodSandboxManagerServiceImpl::GetIPs(const std::string &podSandboxID, const
error.Clear();
}
-void PodSandboxManagerServiceImpl::SetSandboxStatusNetwork(const container_inspect *inspect,
- const std::string &podSandboxID,
- std::unique_ptr<runtime::v1alpha2::PodSandboxStatus> &podStatus,
- Errors &error)
+void PodSandboxManagerServiceImpl::SetSandboxStatusNetwork(
+ const container_inspect *inspect, const std::string &podSandboxID,
+ std::unique_ptr<runtime::v1alpha2::PodSandboxStatus> &podStatus, Errors &error)
{
std::vector<std::string> ips;
size_t i;
@@ -1052,10 +1107,9 @@ void PodSandboxManagerServiceImpl::SetSandboxStatusNetwork(const container_inspe
}
}
-void PodSandboxManagerServiceImpl::PodSandboxStatusToGRPC(const container_inspect *inspect,
- const std::string &podSandboxID,
- std::unique_ptr<runtime::v1alpha2::PodSandboxStatus> &podStatus,
- Errors &error)
+void PodSandboxManagerServiceImpl::PodSandboxStatusToGRPC(
+ const container_inspect *inspect, const std::string &podSandboxID,
+ std::unique_ptr<runtime::v1alpha2::PodSandboxStatus> &podStatus, Errors &error)
{
int64_t createdAt {};
runtime::v1alpha2::NamespaceOption *options { nullptr };
@@ -1129,8 +1183,8 @@ PodSandboxManagerServiceImpl::PodSandboxStatus(const std::string &podSandboxID,
}
void PodSandboxManagerServiceImpl::ListPodSandboxFromGRPC(const runtime::v1alpha2::PodSandboxFilter *filter,
- container_list_request **request, bool *filterOutReadySandboxes,
- Errors &error)
+ container_list_request **request,
+ bool *filterOutReadySandboxes, Errors &error)
{
*request = (container_list_request *)util_common_calloc_s(sizeof(container_list_request));
if (*request == nullptr) {
@@ -1175,9 +1229,9 @@ void PodSandboxManagerServiceImpl::ListPodSandboxFromGRPC(const runtime::v1alpha
}
}
-void PodSandboxManagerServiceImpl::ListPodSandboxToGRPC(container_list_response *response,
- std::vector<std::unique_ptr<runtime::v1alpha2::PodSandbox>> *pods,
- bool filterOutReadySandboxes, Errors &error)
+void PodSandboxManagerServiceImpl::ListPodSandboxToGRPC(
+ container_list_response *response, std::vector<std::unique_ptr<runtime::v1alpha2::PodSandbox>> *pods,
+ bool filterOutReadySandboxes, Errors &error)
{
for (size_t i = 0; i < response->containers_len; i++) {
std::unique_ptr<runtime::v1alpha2::PodSandbox> pod(new runtime::v1alpha2::PodSandbox);
diff --git a/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.h b/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.h
index fa5d153c..34907fa6 100644
--- a/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.h
+++ b/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.h
@@ -82,7 +82,7 @@ private:
void SetNetworkReady(const std::string &podSandboxID, bool ready, Errors &error);
void StartSandboxContainer(const std::string &response_id, Errors &error);
void SetupSandboxNetwork(const runtime::v1alpha2::PodSandboxConfig &config, const std::string &response_id,
- const std::string &jsonCheckpoint, Errors &error);
+ const std::string &jsonCheckpoint, const container_inspect *inspect_data, Errors &error);
void SetupSandboxFiles(const std::string &resolvPath, const runtime::v1alpha2::PodSandboxConfig &config,
Errors &error);
void StopContainerHelper(const std::string &containerID, Errors &error);
diff --git a/src/daemon/entry/cri/cri_security_context.cc b/src/daemon/entry/cri/cri_security_context.cc
index b6a5fcdc..3ff8a0cb 100644
--- a/src/daemon/entry/cri/cri_security_context.cc
+++ b/src/daemon/entry/cri/cri_security_context.cc
@@ -169,6 +169,9 @@ static void ModifyHostNetworkOptionForSandbox(const runtime::v1alpha2::Namespace
hostConfig->network_mode = util_strdup_s(CRI::Constants::namespaceModeHost.c_str());
free(hostConfig->uts_mode);
hostConfig->uts_mode = util_strdup_s(CRI::Constants::namespaceModeHost.c_str());
+ } else {
+ free(hostConfig->network_mode);
+ hostConfig->network_mode = util_strdup_s(CRI::Constants::namespaceModeFile.c_str());
}
// Note: default networkMode is not supported
}
diff --git a/src/daemon/executor/container_cb/execution_create.c b/src/daemon/executor/container_cb/execution_create.c
index 05c0fd78..95a7d9ab 100644
--- a/src/daemon/executor/container_cb/execution_create.c
+++ b/src/daemon/executor/container_cb/execution_create.c
@@ -46,6 +46,7 @@
#include "utils.h"
#include "error.h"
#include "constants.h"
+#include "namespace.h"
#include "events_sender_api.h"
#include "sysinfo.h"
#include "service_container_api.h"
@@ -58,6 +59,7 @@
#include "utils_verify.h"
#include "selinux_label.h"
#include "opt_log.h"
+#include "network_namespace_api.h"
static int do_init_cpurt_cgroups_path(const char *path, int recursive_depth, const char *mnt_root,
int64_t cpu_rt_period, int64_t cpu_rt_runtime);
@@ -1395,6 +1397,63 @@ out:
return res;
}
+static char *new_pod_sandbox_key(void)
+{
+ int nret = 0;
+ char random[NETNS_LEN + 1] = { 0x00 };
+ char netns[PATH_MAX] = { 0x00 };
+ const char *netns_fmt = "/var/run/netns/isulacni-%s";
+
+ nret = util_generate_random_str(random, NETNS_LEN);
+ if (nret != 0) {
+ ERROR("Failed to generate random netns");
+ return NULL;
+ }
+
+ nret = snprintf(netns, sizeof(netns), netns_fmt, random);
+ if (nret < 0 || (size_t)nret >= sizeof(netns)) {
+ ERROR("snprintf netns failed");
+ return NULL;
+ }
+
+ return util_strdup_s(netns);
+}
+
+static int generate_network_settings(const host_config *host_config, container_config_v2_common_config *v2_spec)
+{
+ container_config_v2_common_config_network_settings *settings = NULL;
+
+ if (!namespace_is_file(host_config->network_mode)) {
+ return 0;
+ }
+
+ settings = (container_config_v2_common_config_network_settings *)util_common_calloc_s(sizeof(
+ container_config_v2_common_config_network_settings));
+ if (settings == NULL) {
+ ERROR("Out of memory");
+ return -1;
+ }
+
+ settings->sandbox_key = new_pod_sandbox_key();
+ if (settings->sandbox_key == NULL) {
+ ERROR("Failed to generate sandbox key");
+ goto err_out;
+ }
+
+ if (prepare_network_namespace(settings->sandbox_key) != 0) {
+ ERROR("Failed to create network namespace");
+ goto err_out;
+ }
+
+ v2_spec->network_settings = settings;
+
+ return 0;
+
+err_out:
+ free_container_config_v2_common_config_network_settings(settings);
+ return -1;
+}
+
static int cpurt_controller_init(const char *cgroups_path)
{
int ret = 0;
@@ -1568,6 +1627,12 @@ int container_create_cb(const container_create_request *request, container_creat
goto umount_shm;
}
+ if (generate_network_settings(host_spec, v2_spec) != 0) {
+ ERROR("Failed to generate network settings");
+ cc = ISULAD_ERR_EXEC;
+ goto umount_shm;
+ }
+
if (merge_config_for_syscontainer(request, host_spec, v2_spec->config, oci_spec) != 0) {
ERROR("Failed to merge config for syscontainer");
cc = ISULAD_ERR_EXEC;
diff --git a/src/daemon/executor/container_cb/execution_network.c b/src/daemon/executor/container_cb/execution_network.c
index 2c662bc1..5532e3fc 100644
--- a/src/daemon/executor/container_cb/execution_network.c
+++ b/src/daemon/executor/container_cb/execution_network.c
@@ -34,6 +34,7 @@
#include "err_msg.h"
#include "utils_file.h"
#include "utils_string.h"
+#include "network_namespace_api.h"
static int write_hostname_to_file(const char *rootfs, const char *hostname)
{
@@ -1038,4 +1039,4 @@ int init_container_network_confs(const char *id, const char *rootpath, const hos
out:
return ret;
-}
+}
\ No newline at end of file
diff --git a/src/daemon/executor/container_cb/execution_network.h b/src/daemon/executor/container_cb/execution_network.h
index dee56fed..b6428b05 100644
--- a/src/daemon/executor/container_cb/execution_network.h
+++ b/src/daemon/executor/container_cb/execution_network.h
@@ -29,7 +29,6 @@ extern "C" {
int merge_network(const host_config *host_spec, const char *rootfs, const char *runtime_root,
const char *id, const char *hostname);
-
int init_container_network_confs(const char *id, const char *rootpath, const host_config *hc,
container_config_v2_common_config *common_config);
diff --git a/src/daemon/modules/api/network_namespace_api.h b/src/daemon/modules/api/network_namespace_api.h
new file mode 100644
index 00000000..9a18b1c0
--- /dev/null
+++ b/src/daemon/modules/api/network_namespace_api.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2021. 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: chengzeruizhi
+ * Create: 2021-10-19
+ * Description: set up CRI network namespace
+ *********************************************************************************/
+
+#ifndef DAEMON_MODULES_API_NETWORK_NAMESPACE_API
+#define DAEMON_MODULES_API_NETWORK_NAMESPACE_API
+
+#include <stdbool.h>
+
+#include "container_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int prepare_network_namespace(const char *netns_path);
+int remove_network_namespace(const char *netns);
+char *get_sandbox_key(const container_inspect *inspect_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DAEMON_MODULES_API_NETWORK_NAMESPACE_API
diff --git a/src/daemon/modules/api/specs_api.h b/src/daemon/modules/api/specs_api.h
index 6c4db007..c4ad79aa 100644
--- a/src/daemon/modules/api/specs_api.h
+++ b/src/daemon/modules/api/specs_api.h
@@ -37,7 +37,9 @@ int save_oci_config(const char *id, const char *rootpath, const oci_runtime_spec
int parse_security_opt(const host_config *host_spec, bool *no_new_privileges, char ***label_opts,
size_t *label_opts_len, char **seccomp_profile);
-int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_spec);
+int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/daemon/modules/container/container_unix.c b/src/daemon/modules/container/container_unix.c
index 1904161e..98f91ea9 100644
--- a/src/daemon/modules/container/container_unix.c
+++ b/src/daemon/modules/container/container_unix.c
@@ -45,6 +45,7 @@
#include "utils_file.h"
#include "utils_string.h"
#include "volume_api.h"
+#include "namespace.h"
static int parse_container_log_configs(container_t *cont);
diff --git a/src/daemon/modules/service/inspect_container.c b/src/daemon/modules/service/inspect_container.c
index d678f7bb..b060fe12 100644
--- a/src/daemon/modules/service/inspect_container.c
+++ b/src/daemon/modules/service/inspect_container.c
@@ -31,6 +31,7 @@
#include "container_api.h"
#include "isulad_config.h"
#include "err_msg.h"
+#include "namespace.h"
static int dup_path_and_args(const container_t *cont, char **path, char ***args, size_t *args_len)
{
@@ -458,6 +459,36 @@ out:
return ret;
}
+static int pack_inspect_network_settings(const container_t *cont, container_inspect *inspect)
+{
+ if (cont == NULL || cont->common_config == NULL) {
+ ERROR("Failed to get v2 common config from container");
+ return -1;
+ }
+
+ if (!namespace_is_file(cont->hostconfig->network_mode)) {
+ return 0;
+ }
+
+ if (cont->common_config->network_settings == NULL) {
+ ERROR("Failed to get network settings from container");
+ return -1;
+ }
+
+ if (inspect->network_settings == NULL) {
+ inspect->network_settings =
+ (container_inspect_network_settings *)util_common_calloc_s(sizeof(container_inspect_network_settings));
+ if (inspect->network_settings == NULL) {
+ ERROR("Out of memory");
+ return -1;
+ }
+ }
+
+ inspect->network_settings->sandbox_key = util_strdup_s(cont->common_config->network_settings->sandbox_key);
+
+ return 0;
+}
+
static int merge_default_ulimit_with_ulimit(container_inspect *out_inspect)
{
int ret = 0;
@@ -509,6 +540,10 @@ static container_inspect *pack_inspect_data(const container_t *cont, bool with_h
ERROR("Failed to pack inspect general data, continue to pack other information");
}
+ if (pack_inspect_network_settings(cont, inspect) != 0) {
+ ERROR("Failed to pack inspect network settings, continue to pack other information");
+ }
+
if (pack_inspect_container_state(cont, inspect) != 0) {
ERROR("Failed to pack inspect state data, continue to pack other information");
}
diff --git a/src/daemon/modules/service/network_namespace_api.c b/src/daemon/modules/service/network_namespace_api.c
new file mode 100644
index 00000000..e28e6f74
--- /dev/null
+++ b/src/daemon/modules/service/network_namespace_api.c
@@ -0,0 +1,80 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2021. 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: chengzeruizhi
+ * Create: 2021-10-19
+ * Description: set up CRI network namespace
+ *********************************************************************************/
+#define _GNU_SOURCE
+
+#include "network_namespace_api.h"
+
+#include <sys/mount.h>
+
+#include "utils_network.h"
+
+int prepare_network_namespace(const char *netns_path)
+{
+ if (netns_path == NULL) {
+ ERROR("Invalid netns_path");
+ return -1;
+ }
+
+ if (util_create_netns_file(netns_path) != 0) {
+ ERROR("Failed to prepare network namespace file");
+ return -1;
+ }
+
+ return 0;
+}
+
+int remove_network_namespace(const char *netns_path)
+{
+ int get_err = 0;
+
+ if (netns_path == NULL) {
+ ERROR("Invalid netns_path");
+ return -1;
+ }
+
+ if (!util_file_exists(netns_path)) {
+ WARN("Namespace file does not exist");
+ return 0;
+ }
+
+ if (umount2(netns_path, MNT_DETACH) != 0 && errno != EINVAL) {
+ ERROR("Failed to umount directory %s:%s", netns_path, strerror(errno));
+ return -1;
+ }
+
+ if (!util_force_remove_file(netns_path, &get_err)) {
+ ERROR("Failed to remove file %s, error: %s", netns_path, strerror(get_err));
+ return -1;
+ }
+
+ return 0;
+}
+
+char *get_sandbox_key(const container_inspect *inspect_data)
+{
+ char *sandbox_key = NULL;
+
+ if (inspect_data == NULL) {
+ ERROR("Invalid container");
+ return NULL;
+ }
+ if (inspect_data->network_settings == NULL) {
+ ERROR("Inspect data does not have network settings");
+ return NULL;
+ }
+ sandbox_key = util_strdup_s(inspect_data->network_settings->sandbox_key);
+
+ return sandbox_key;
+}
\ No newline at end of file
diff --git a/src/daemon/modules/service/service_container.c b/src/daemon/modules/service/service_container.c
index 0bcfb0e9..27288f6d 100644
--- a/src/daemon/modules/service/service_container.c
+++ b/src/daemon/modules/service/service_container.c
@@ -59,6 +59,8 @@
#include "utils_string.h"
#include "utils_verify.h"
#include "volume_api.h"
+#include "utils_network.h"
+#include "network_namespace_api.h"
#define KATA_RUNTIME "kata-runtime"
@@ -227,7 +229,7 @@ static int renew_oci_config(const container_t *cont, oci_runtime_spec *oci_spec)
goto out;
}
- ret = merge_share_namespace(oci_spec, cont->hostconfig);
+ ret = merge_share_namespace(oci_spec, cont->hostconfig, cont->common_config->network_settings);
if (ret != 0) {
ERROR("Failed to merge share ns");
goto out;
@@ -895,6 +897,10 @@ int start_container(container_t *cont, const char *console_fifos[], bool reset_r
}
set_stopped:
+ if (namespace_is_file(cont->hostconfig->network_mode) &&
+ util_umount_namespace(cont->common_config->network_settings->sandbox_key) != 0) {
+ ERROR("Failed to clean up network namespace");
+ }
container_state_set_error(cont->state, (const char *)g_isulad_errmsg);
util_contain_errmsg(g_isulad_errmsg, &exit_code);
container_state_set_stopped(cont->state, exit_code);
@@ -1085,6 +1091,13 @@ static int do_delete_container(container_t *cont)
goto out;
}
+ // clean up mounted network namespace
+ if (cont->common_config->network_settings != NULL &&
+ util_file_exists(cont->common_config->network_settings->sandbox_key)
+ && remove_network_namespace(cont->common_config->network_settings->sandbox_key) != 0) {
+ ERROR("Failed to remove network when deleting container %s", cont->common_config->id);
+ }
+
ret = snprintf(container_state, sizeof(container_state), "%s/%s", statepath, id);
if (ret < 0 || (size_t)ret >= sizeof(container_state)) {
ERROR("Failed to sprintf container_state");
diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c
index d8d05ba0..fc53bd14 100644
--- a/src/daemon/modules/spec/specs.c
+++ b/src/daemon/modules/spec/specs.c
@@ -22,14 +22,14 @@
#include <isula_libutils/defs.h>
#include <isula_libutils/json_common.h>
#include <isula_libutils/oci_runtime_config_linux.h>
+#include <isula_libutils/oci_runtime_spec.h>
+#include <isula_libutils/oci_runtime_hooks.h>
+#include <isula_libutils/host_config.h>
+#include <isula_libutils/log.h>
#include <limits.h>
#include <stdint.h>
-#include "isula_libutils/log.h"
#include "specs_api.h"
-#include "isula_libutils/oci_runtime_spec.h"
-#include "isula_libutils/oci_runtime_hooks.h"
-#include "isula_libutils/host_config.h"
#include "utils.h"
#include "isulad_config.h"
#include "namespace.h"
@@ -1377,10 +1377,9 @@ out:
return ret;
}
-static int merge_share_namespace_helper(const oci_runtime_spec *oci_spec, const char *path, const char *type)
+static int merge_share_namespace_helper(const oci_runtime_spec *oci_spec, const char *ns_path, const char *type)
{
int ret = -1;
- char *ns_path = NULL;
size_t len = 0;
size_t org_len = 0;
size_t i = 0;
@@ -1390,11 +1389,6 @@ static int merge_share_namespace_helper(const oci_runtime_spec *oci_spec, const
len = oci_spec->linux->namespaces_len;
work_ns = oci_spec->linux->namespaces;
- ret = get_share_namespace_path(type, path, &ns_path);
- if (ret != 0) {
- ERROR("Failed to get share ns type:%s path:%s", type, path);
- goto out;
- }
for (i = 0; i < org_len; i++) {
if (strcmp(type, work_ns[i]->type) == 0) {
free(work_ns[i]->path);
@@ -1433,7 +1427,6 @@ static int merge_share_namespace_helper(const oci_runtime_spec *oci_spec, const
}
ret = 0;
out:
- free(ns_path);
if (work_ns != NULL) {
oci_spec->linux->namespaces = work_ns;
oci_spec->linux->namespaces_len = len;
@@ -1443,14 +1436,55 @@ out:
static int merge_share_single_namespace(const oci_runtime_spec *oci_spec, const char *path, const char *type)
{
+ int ret = 0;
+ char *ns_path = NULL;
+
if (path == NULL) {
return 0;
}
- return merge_share_namespace_helper(oci_spec, path, type);
+ ret = get_share_namespace_path(type, path, &ns_path);
+ if (ret != 0) {
+ ERROR("Failed to get share ns type:%s path:%s", type, path);
+ return -1;
+ }
+
+ ret = merge_share_namespace_helper(oci_spec, ns_path, type);
+ if (ret != 0) {
+ ERROR("Failed to merge share namespace namespace helper");
+ }
+
+ free(ns_path);
+ return ret;
+}
+
+static int merge_share_network_namespace(oci_runtime_spec *oci_spec, const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings, const char *type)
+{
+ int ret = 0;
+ char *ns_path = NULL;
+
+ if (host_spec->network_mode == NULL) {
+ return 0;
+ }
+
+ ret = get_network_namespace_path(host_spec, network_settings, type, &ns_path);
+ if (ret != 0) {
+ ERROR("Failed to get network namespace path");
+ return -1;
+ }
+
+ ret = merge_share_namespace_helper(oci_spec, ns_path, type);
+ if (ret != 0) {
+ ERROR("Failed to merge share namespace namespace helper");
+ }
+
+ free(ns_path);
+ return ret;
}
-int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_spec)
+int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings)
{
int ret = -1;
@@ -1475,7 +1509,7 @@ int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_sp
}
// network
- if (merge_share_single_namespace(oci_spec, host_spec->network_mode, TYPE_NAMESPACE_NETWORK) != 0) {
+ if (merge_share_network_namespace(oci_spec, host_spec, network_settings, TYPE_NAMESPACE_NETWORK) != 0) {
ret = -1;
goto out;
}
diff --git a/src/daemon/modules/spec/specs_namespace.c b/src/daemon/modules/spec/specs_namespace.c
index e291f092..eea0b3ff 100644
--- a/src/daemon/modules/spec/specs_namespace.c
+++ b/src/daemon/modules/spec/specs_namespace.c
@@ -17,15 +17,16 @@
#include <string.h>
#include <stdlib.h>
#include <limits.h>
-#include <isula_libutils/container_config_v2.h>
#include <signal.h>
#include <stdio.h>
+#include <isula_libutils/log.h>
+#include <isula_libutils/container_config_v2.h>
-#include "isula_libutils/log.h"
#include "utils.h"
#include "namespace.h"
#include "container_api.h"
#include "err_msg.h"
+#include "network_namespace_api.h"
static char *parse_share_namespace_with_prefix(const char *type, const char *path)
{
@@ -133,3 +134,84 @@ char *get_container_process_label(const char *cid)
out:
return result;
}
+
+typedef int (*namespace_mode_check)(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings,
+ const char *type, char **dest_path);
+
+struct get_netns_path_handler {
+ char *mode;
+ namespace_mode_check handle;
+};
+
+static int handle_get_path_from_none(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings,
+ const char *type, char **dest_path)
+{
+ *dest_path = NULL;
+ return 0;
+}
+
+static int handle_get_path_from_host(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings,
+ const char *type, char **dest_path)
+{
+ *dest_path = namespace_get_host_namespace_path(host_spec->network_mode);
+ if (*dest_path == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static int handle_get_path_from_container(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings, const char *type,
+ char **dest_path)
+{
+ *dest_path = parse_share_namespace_with_prefix(type, host_spec->network_mode);
+ if (*dest_path == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static int handle_get_path_from_file(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings,
+ const char *type, char **dest_path)
+{
+ if (network_settings == NULL || network_settings->sandbox_key == NULL) {
+ ERROR("Invalid sandbox key for file mode network");
+ return -1;
+ }
+
+ *dest_path = util_strdup_s(network_settings->sandbox_key);
+ return 0;
+}
+
+int get_network_namespace_path(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings,
+ const char *type, char **dest_path)
+{
+ int index;
+ int ret = -1;
+ struct get_netns_path_handler handler_jump_table[] = {
+ { SHARE_NAMESPACE_NONE, handle_get_path_from_none },
+ { SHARE_NAMESPACE_HOST, handle_get_path_from_host },
+ { SHARE_NAMESPACE_PREFIX, handle_get_path_from_container },
+ { SHARE_NAMESPACE_FILE, handle_get_path_from_file },
+ };
+ size_t jump_table_size = sizeof(handler_jump_table) / sizeof(handler_jump_table[0]);
+ const char *network_mode = host_spec->network_mode;
+
+ if (network_mode == NULL || dest_path == NULL) {
+ return -1;
+ }
+
+ for (index = 0; index < jump_table_size; ++index) {
+ if (strncmp(network_mode, handler_jump_table[index].mode, strlen(handler_jump_table[index].mode)) == 0) {
+ ret = handler_jump_table[index].handle(host_spec, network_settings, type, dest_path);
+ return ret;
+ }
+ }
+
+ return ret;
+}
\ No newline at end of file
diff --git a/src/daemon/modules/spec/specs_namespace.h b/src/daemon/modules/spec/specs_namespace.h
index 526ad4e0..68e41399 100644
--- a/src/daemon/modules/spec/specs_namespace.h
+++ b/src/daemon/modules/spec/specs_namespace.h
@@ -17,6 +17,8 @@
#include <stdbool.h>
#include <string.h>
+#include <isula_libutils/host_config.h>
+#include <isula_libutils/container_config_v2.h>
#ifdef __cplusplus
extern "C" {
@@ -24,6 +26,9 @@ extern "C" {
int get_share_namespace_path(const char *type, const char *src_path, char **dest_path);
char *get_container_process_label(const char *path);
+int get_network_namespace_path(const host_config *host_spec,
+ const container_config_v2_common_config_network_settings *network_settings,
+ const char *type, char **dest_path);
#ifdef __cplusplus
}
diff --git a/src/utils/cutils/namespace.h b/src/utils/cutils/namespace.h
index cf768056..26a9bb19 100644
--- a/src/utils/cutils/namespace.h
+++ b/src/utils/cutils/namespace.h
@@ -37,6 +37,8 @@ typedef enum {
#define SHARE_NAMESPACE_HOST "host"
#define SHARE_NAMESPACE_NONE "none"
#define SHARE_NAMESPACE_SHAREABLE "shareable"
+#define SHARE_NAMESPACE_BRIDGE "bridge"
+#define SHARE_NAMESPACE_FILE "file"
#define SHARE_NAMESPACE_PID_HOST_PATH "/proc/1/ns/pid"
#define SHARE_NAMESPACE_NET_HOST_PATH "/proc/1/ns/net"
@@ -82,6 +84,22 @@ static inline bool namespace_is_container(const char *mode)
return false;
}
+static inline bool namespace_is_bridge(const char *mode)
+{
+ if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_BRIDGE) == 0) {
+ return true;
+ }
+ return false;
+}
+
+static inline bool namespace_is_file(const char *mode)
+{
+ if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_FILE) == 0) {
+ return true;
+ }
+ return false;
+}
+
static inline bool namespace_is_shareable(const char *mode)
{
if (mode != NULL && strcmp(mode, SHARE_NAMESPACE_SHAREABLE) == 0) {
diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c
index 302e4e32..f4fa4ece 100644
--- a/src/utils/cutils/utils_file.c
+++ b/src/utils/cutils/utils_file.c
@@ -275,6 +275,29 @@ out:
return ret;
}
+bool util_force_remove_file(const char *fname, int *saved_errno)
+{
+ if (unlink(fname) == 0) {
+ return true;
+ }
+
+ WARN("Failed to delete %s: %s", fname, strerror(errno));
+ if (*saved_errno == 0) {
+ *saved_errno = errno;
+ }
+
+ if (mark_file_mutable(fname) != 0) {
+ WARN("Failed to mark file mutable");
+ }
+
+ if (unlink(fname) != 0) {
+ ERROR("Failed to delete \"%s\": %s", fname, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
static int recursive_rmdir_next_depth(struct stat fstat, const char *fname, int recursive_depth, int *saved_errno,
int failure)
{
diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h
index 125f43a3..a7fbbb6b 100644
--- a/src/utils/cutils/utils_file.h
+++ b/src/utils/cutils/utils_file.h
@@ -36,6 +36,8 @@ bool util_file_exists(const char *f);
int util_path_remove(const char *path);
+bool util_force_remove_file(const char *fname, int *saved_errno);
+
ssize_t util_write_nointr(int fd, const void *buf, size_t count);
ssize_t util_write_nointr_in_total(int fd, const char *buf, size_t count);
diff --git a/src/utils/cutils/utils_network.c b/src/utils/cutils/utils_network.c
new file mode 100644
index 00000000..a5d77c93
--- /dev/null
+++ b/src/utils/cutils/utils_network.c
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2021. 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: chengzeruizhi
+ * Create: 2021-11-17
+ * Description: provide common network functions
+ ********************************************************************************/
+
+#define _GNU_SOURCE
+
+#include "utils_network.h"
+
+#include <unistd.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+#include <syscall.h>
+#include <isula_libutils/log.h>
+#include <fcntl.h>
+
+#include "utils_fs.h"
+#include "utils_file.h"
+#include "constants.h"
+
+int util_create_netns_file(const char *netns_path)
+{
+ int ret = 0;
+ int fd = -1;
+ char *netns_dir = NULL;
+
+ if (util_file_exists(netns_path)) {
+ ERROR("Namespace file %s exists", netns_path);
+ return -1;
+ }
+ netns_dir = util_path_dir(netns_path);
+ if (netns_dir == NULL) {
+ ERROR("Failed to get path dir for %s", netns_path);
+ return -1;
+ }
+ if (!util_dir_exists(netns_dir) && util_mkdir_p(netns_dir, DEFAULT_HIGHEST_DIRECTORY_MODE) != 0) {
+ ERROR("Failed to create directory for %s", netns_path);
+ ret = -1;
+ goto out;
+ }
+
+ fd = util_open(netns_path, O_RDWR | O_CREAT | O_TRUNC, DEFAULT_SECURE_FILE_MODE);
+ if (fd < 0) {
+ ERROR("Failed to create namespace file: %s", netns_path);
+ ret = -1;
+ goto out;
+ }
+ close(fd);
+
+out:
+ free(netns_dir);
+ return ret;
+}
+
+static void mount_netns(void *netns_path)
+{
+ int failure = EXIT_FAILURE;
+ int success = EXIT_SUCCESS;
+ char fullpath[PATH_MAX] = { 0x00 };
+ int ret = 0;
+
+ if (unshare(CLONE_NEWNET) != 0) {
+ pthread_exit((void *)&failure);
+ }
+
+ ret = snprintf(fullpath, sizeof(fullpath), "/proc/%d/task/%ld/ns/net", getpid(), (long int)syscall(__NR_gettid));
+ if (ret < 0 || (size_t)ret >= sizeof(fullpath)) {
+ pthread_exit((void *)&failure);
+ }
+
+ if (util_mount(fullpath, (char *)netns_path, "none", "bind") != 0) {
+ pthread_exit((void *)&failure);
+ }
+ pthread_exit((void *)&success);
+}
+
+// this function mounts netns path to /proc/%d/task/%d/ns/net
+int util_mount_namespace(const char *netns_path)
+{
+ pthread_t newns_thread = 0;
+ int ret = 0;
+ void *status = NULL;
+
+ ret = pthread_create(&newns_thread, NULL, (void *)&mount_netns, (void *)netns_path);
+ if (ret != 0) {
+ ERROR("Failed to create thread");
+ return -1;
+ }
+
+ ret = pthread_join(newns_thread, &status);
+ if (ret != 0) {
+ ERROR("Failed to join thread");
+ return -1;
+ } else {
+ if (*(int *)status != 0) {
+ ERROR("Failed to initialize network namespace");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int util_umount_namespace(const char *netns_path)
+{
+ int i = 0;
+ if (netns_path == NULL) {
+ WARN("Invalid path to umount");
+ }
+
+ for (i = 0; i < 50; i++) {
+ if (umount2(netns_path, MNT_DETACH) < 0) {
+ switch (errno) {
+ case EBUSY:
+ usleep(50);
+ continue;
+ case EINVAL:
+ return 0;
+ default:
+ continue;
+ }
+ }
+ }
+ ERROR("Failed to umount target %s", netns_path);
+ return -1;
+}
diff --git a/src/utils/cutils/utils_network.h b/src/utils/cutils/utils_network.h
new file mode 100644
index 00000000..6ec912d8
--- /dev/null
+++ b/src/utils/cutils/utils_network.h
@@ -0,0 +1,33 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2021. 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: chengzeruizhi
+ * Create: 2021-11-17
+ * Description: provide common network functions
+ ********************************************************************************/
+
+#ifndef UTILS_CUTILS_UTILS_NETWORK_H
+#define UTILS_CUTILS_UTILS_NETWORK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int util_create_netns_file(const char *netns_path);
+
+int util_mount_namespace(const char *netns_path);
+
+int util_umount_namespace(const char *netns_path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // UTILS_CUTILS_UTILS_NETWORK_H
\ No newline at end of file
--
2.25.1