feat: 支持网络容器

BREAKING CHANGE:
支持网络容器对外变更:
1.支持网络容器
2.setns, clone, unshare接口支持CLONE_NEWNET

Close #I6HPH2

Signed-off-by: zhushengle <zhushengle@huawei.com>
Change-Id: Ibaa11056982d465d4006680c8d3fa4ae2b9f25b5
This commit is contained in:
zhushengle
2023-02-24 09:45:59 +08:00
parent 806bd80841
commit 5dc9a0f1a6
46 changed files with 2765 additions and 69 deletions

View File

@@ -143,6 +143,7 @@ LOSCFG_USER_TEST_MNT_CONTAINER = false
LOSCFG_USER_TEST_IPC_CONTAINER = false
LOSCFG_USER_TEST_TIME_CONTAINER = false
LOSCFG_USER_TEST_USER_CONTAINER = false
LOSCFG_USER_TEST_NET_CONTAINER = false
if (defined(LOSCFG_KERNEL_CONTAINER) || liteos_container_test_enable == true) {
LOSCFG_USER_TEST_CONTAINER = true
if (defined(LOSCFG_PID_CONTAINER) || liteos_container_test_enable == true) {
@@ -163,6 +164,9 @@ if (defined(LOSCFG_KERNEL_CONTAINER) || liteos_container_test_enable == true) {
if (defined(LOSCFG_USER_CONTAINER) || liteos_container_test_enable == true) {
LOSCFG_USER_TEST_USER_CONTAINER = true
}
if (defined(LOSCFG_NET_CONTAINER) || liteos_container_test_enable == true) {
LOSCFG_USER_TEST_NET_CONTAINER = true
}
}
LOSCFG_USER_TEST_PROCESS_PLIMITS = false

View File

@@ -50,6 +50,9 @@ config("container_config") {
if (defined(LOSCFG_USER_TEST_USER_CONTAINER)) {
cflags += [ "-DLOSCFG_USER_TEST_USER_CONTAINER" ]
}
if (defined(LOSCFG_USER_TEST_NET_CONTAINER)) {
cflags += [ "-DLOSCFG_USER_TEST_NET_CONTAINER" ]
}
cflags_cc = cflags
}

View File

@@ -181,7 +181,151 @@ HWTEST_F(ContainerTest, ItContainer001, TestSize.Level0)
{
ItContainer001();
}
#if defined(LOSCFG_USER_TEST_NET_CONTAINER)
/**
* @tc.name: Container_NET_Test_001
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer001, TestSize.Level0)
{
ItNetContainer001();
}
/**
* @tc.name: Container_NET_Test_002
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer002, TestSize.Level0)
{
ItNetContainer002();
}
/**
* @tc.name: Container_NET_Test_003
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer003, TestSize.Level0)
{
ItNetContainer003();
}
/**
* @tc.name: Container_NET_Test_004
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer004, TestSize.Level0)
{
ItNetContainer004();
}
/**
* @tc.name: Container_NET_Test_005
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer005, TestSize.Level0)
{
ItNetContainer005();
}
/**
* @tc.name: Container_NET_Test_006
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer006, TestSize.Level0)
{
ItNetContainer006();
}
/**
* @tc.name: Container_NET_Test_007
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer007, TestSize.Level0)
{
ItNetContainer007();
}
/**
* @tc.name: Container_NET_Test_008
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer008, TestSize.Level0)
{
ItNetContainer008();
}
/**
* @tc.name: Container_NET_Test_009
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer009, TestSize.Level0)
{
ItNetContainer009();
}
/**
* @tc.name: Container_NET_Test_010
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer010, TestSize.Level0)
{
ItNetContainer010();
}
/**
* @tc.name: Container_NET_Test_011
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer011, TestSize.Level0)
{
ItNetContainer011();
}
/**
* @tc.name: Container_NET_Test_012
* @tc.desc: uts container function test case
* @tc.type: FUNC
* @tc.require: issueI6HPH2
* @tc.author:
*/
HWTEST_F(ContainerTest, ItNetContainer012, TestSize.Level0)
{
ItNetContainer012();
}
#endif
#if defined(LOSCFG_USER_TEST_USER_CONTAINER)
/**
* @tc.name: Container_UTS_Test_001

View File

@@ -220,5 +220,16 @@ void ItPidContainer021(void);
void ItPidContainer022(void);
void ItPidContainer024(void);
void ItUtsContainer003(void);
void ItNetContainer001(void);
void ItNetContainer002(void);
void ItNetContainer003(void);
void ItNetContainer004(void);
void ItNetContainer005(void);
void ItNetContainer006(void);
void ItNetContainer007(void);
void ItNetContainer008(void);
void ItNetContainer009(void);
void ItNetContainer010(void);
void ItNetContainer011(void);
void ItNetContainer012(void);
#endif /* _IT_CONTAINER_TEST_H */

View File

@@ -149,3 +149,19 @@ if (defined(LOSCFG_USER_TEST_USER_CONTAINER)) {
sources_full +=
[ "$TEST_UNITTEST_DIR/container/full/It_user_container_005.cpp" ]
}
if (defined(LOSCFG_USER_TEST_NET_CONTAINER)) {
sources_smoke += [
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_001.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_002.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_003.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_004.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_005.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_006.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_007.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_008.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_009.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_010.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_011.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_net_container_012.cpp",
]
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <net/if.h>
#include "It_container_test.h"
using namespace std;
const int IpLen = 16;
static int GetLocalIP(char *ip)
{
struct ifreq ifr;
int inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (inet_sock < 0) {
return -1;
}
int ret = strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
if (ret != EOK) {
(void)close(inet_sock);
return -1;
}
ioctl(inet_sock, SIOCGIFADDR, &ifr);
ret = strcpy_s(ip, IpLen, inet_ntoa((reinterpret_cast<struct sockaddr_in *>(&ifr.ifr_addr))->sin_addr));
if (ret != EOK) {
(void)close(inet_sock);
return -1;
}
ret = close(inet_sock);
if (ret != 0) {
return -1;
}
return 0;
}
static int SetIP(char *ip)
{
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (fd < 0) {
return -1;
}
int ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0", IFNAMSIZ);
if (ret != EOK) {
(void)close(fd);
return -1;
}
ifr.ifr_addr.sa_family = AF_INET;
inet_pton(AF_INET, ip, ifr.ifr_addr.sa_data + 2); /* 2: offset */
ioctl(fd, SIOCSIFADDR, &ifr);
ret = close(fd);
if (ret != 0) {
return -1;
}
return 0;
}
static int ChildFunc(void *arg)
{
(void)arg;
int ret;
char oldIp[IpLen] = {NULL};
char newIp[IpLen] = {NULL};
ret = GetLocalIP(oldIp);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
ret = SetIP("192.168.1.233");
if (ret != 0) {
return EXIT_CODE_ERRNO_2;
}
ret = GetLocalIP(newIp);
if (ret != 0) {
return EXIT_CODE_ERRNO_3;
}
ret = strcmp(oldIp, newIp);
if (ret == 0) {
return EXIT_CODE_ERRNO_4;
}
printf("%s %d\n", __FUNCTION__, __LINE__);
return 0;
}
void ItNetContainer001(void)
{
int ret;
char oldIp[IpLen] = {NULL};
char newIp[IpLen] = {NULL};
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, NULL);
char *stackTop = stack + STACK_SIZE;
ret = GetLocalIP(oldIp);
ASSERT_EQ(ret, 0);
int arg = CHILD_FUNC_ARG;
auto pid = clone(ChildFunc, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
int status;
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
ret = GetLocalIP(newIp);
ASSERT_EQ(ret, 0);
ret = strcmp(oldIp, newIp);
ASSERT_EQ(ret, 0);
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <net/if.h>
#include "It_container_test.h"
using namespace std;
const int IpLen = 16;
static int GetLocalIP(char *ip)
{
struct ifreq ifr;
int inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (inet_sock < 0) {
return -1;
}
int ret = strcpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
if (ret != EOK) {
(void)close(inet_sock);
return -1;
}
ioctl(inet_sock, SIOCGIFADDR, &ifr);
ret = strcpy_s(ip, IpLen, inet_ntoa((reinterpret_cast<struct sockaddr_in *>(&ifr.ifr_addr))->sin_addr));
if (ret != EOK) {
(void)close(inet_sock);
return -1;
}
ret = close(inet_sock);
if (ret != 0) {
return -1;
}
return 0;
}
static int SetIP(char *ip)
{
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (fd < 0) {
return -1;
}
int ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0", IFNAMSIZ);
if (ret != EOK) {
(void)close(fd);
return -1;
}
ifr.ifr_addr.sa_family = AF_INET;
inet_pton(AF_INET, ip, ifr.ifr_addr.sa_data + 2); /* 2: offset */
ioctl(fd, SIOCSIFADDR, &ifr);
ret = close(fd);
if (ret != 0) {
return -1;
}
return 0;
}
static int ChildFunc(void *arg)
{
(void)arg;
int ret;
char oldIp[IpLen] = {NULL};
char newIp[IpLen] = {NULL};
ret = GetLocalIP(oldIp);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
ret = unshare(CLONE_NEWNET);
if (ret < 0) {
return EXIT_CODE_ERRNO_2;
}
ret = SetIP("192.168.1.234");
if (ret != 0) {
return EXIT_CODE_ERRNO_3;
}
ret = GetLocalIP(newIp);
if (ret != 0) {
return EXIT_CODE_ERRNO_4;
}
ret = strcmp(oldIp, newIp);
if (ret == 0) {
return EXIT_CODE_ERRNO_5;
}
return 0;
}
void ItNetContainer002(void)
{
int ret;
char oldIp[IpLen] = {NULL};
char newIp[IpLen] = {NULL};
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, NULL);
char *stackTop = stack + STACK_SIZE;
ret = GetLocalIP(oldIp);
ASSERT_EQ(ret, 0);
int arg = CHILD_FUNC_ARG;
auto pid = clone(ChildFunc, stackTop, SIGCHLD, &arg);
ASSERT_NE(pid, -1);
int status;
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
ret = GetLocalIP(newIp);
ASSERT_EQ(ret, 0);
ret = strcmp(oldIp, newIp);
ASSERT_EQ(ret, 0);
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string>
#include <iostream>
#include <regex>
#include "It_container_test.h"
static std::string GenNetLinkPath(int pid)
{
std::ostringstream buf;
buf << "/proc/" << pid << "/container/net";
return buf.str();
}
static std::string ReadlinkNet(int pid)
{
auto path = GenNetLinkPath(pid);
struct stat sb;
int ret = lstat(path.data(), &sb);
if (ret == -1) {
perror("lstat");
return std::string();
}
auto bufsiz = sb.st_size + 1;
if (sb.st_size == 0) {
bufsiz = PATH_MAX;
}
std::vector<char> buf(bufsiz);
auto nbytes = readlink(path.c_str(), buf.data(), bufsiz);
if (nbytes == -1) {
perror("readlink");
return std::string();
}
return buf.data();
}
void ItNetContainer003(void)
{
std::string zerolink("'net:[0]'");
auto netlink = ReadlinkNet(getpid());
int ret = zerolink.compare(netlink);
ASSERT_NE(ret, 0);
std::regex reg("'net:\\[[0-9]+\\]'");
ret = std::regex_match(netlink, reg);
ASSERT_EQ(ret, 1);
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <iostream>
#include <regex>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "It_container_test.h"
static const char *CONTAINER_TYPE = "net";
static const int SLEEP_SECONDS = 2;
static const int TEST_PATH_MAX = 100;
static int NewnetChildFun(void *)
{
sleep(SLEEP_SECONDS);
return 0;
}
static int ChildFun(void *p)
{
(void)p;
int ret;
int status;
char path[TEST_PATH_MAX];
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
auto childPid = clone(NewnetChildFun, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
if (childPid == -1) {
return EXIT_CODE_ERRNO_1;
}
auto oldReadLink = ReadlinkContainer(getpid(), CONTAINER_TYPE);
if (sprintf_s(path, TEST_PATH_MAX, "/proc/%d/container/net", childPid) < 0) {
(void)waitpid(childPid, &status, 0);
return EXIT_CODE_ERRNO_8;
}
int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return EXIT_CODE_ERRNO_2;
}
ret = setns(fd, CLONE_NEWNET);
if (ret != 0) {
(void)close(fd);
return EXIT_CODE_ERRNO_3;
}
ret = close(fd);
if (ret != 0) {
return EXIT_CODE_ERRNO_4;
}
auto newReadLink = ReadlinkContainer(getpid(), CONTAINER_TYPE);
ret = strcmp(oldReadLink.c_str(), newReadLink.c_str());
if (ret == 0) {
return EXIT_CODE_ERRNO_5;
}
ret = waitpid(childPid, &status, 0);
if (ret != childPid) {
return EXIT_CODE_ERRNO_6;
}
int exitCode = WEXITSTATUS(status);
if (exitCode != 0) {
return EXIT_CODE_ERRNO_7;
}
return 0;
}
void ItNetContainer004(void)
{
int status;
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
auto childPid = clone(ChildFun, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(childPid, -1);
int ret = waitpid(childPid, &status, 0);
ASSERT_EQ(ret, childPid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}

View File

@@ -0,0 +1,267 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/route.h>
#include "It_container_test.h"
static const char *NETMASK = "255.255.255.0";
static const char *GW = "192.168.100.1";
static const char *IFNAME = "veth0";
static const char *SERVER_IP = "192.168.100.6";
static const int SERVER_PORT = 8000;
static const char *PEER_IP = "192.168.100.5";
static const int PEER_PORT = 8001;
static const int DATA_LEN = 128;
static const char *SERVER_MSG = "===Hi, I'm Server.===";
static const char *PEER_MSG = "===Hi, I'm Peer.===";
static const int TRY_COUNT = 5;
static const int OFFSET = 2;
static int TryResetNetaddr(const char *ifname, const char *ip, const char *netmask, const char *gw)
{
int ret;
struct ifreq ifr;
struct rtentry rt;
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (fd < 0) {
return -1;
}
ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifname, IFNAMSIZ);
if (ret != EOK) {
(void)close(fd);
return -1;
}
ifr.ifr_addr.sa_family = AF_INET;
inet_pton(AF_INET, netmask, ifr.ifr_addr.sa_data + OFFSET);
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
if (ret == 0) {
inet_pton(AF_INET, ip, ifr.ifr_addr.sa_data + OFFSET);
ret = ioctl(fd, SIOCSIFADDR, &ifr);
if (ret == 0) {
struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in *>(&rt.rt_gateway);
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(GW);
rt.rt_flags = RTF_GATEWAY;
ret = ioctl(fd, SIOCADDRT, &rt);
}
}
if (ret != 0) {
(void)close(fd);
return ret;
}
ret = close(fd);
return ret;
}
static int ResetNetaddr(const char *ifname, const char *ip, const char *netmask, const char *gw)
{
int ret;
int try_count = TRY_COUNT;
while (try_count--) {
ret = TryResetNetaddr(ifname, ip, netmask, gw);
if (ret == 0) {
break;
}
sleep(1);
}
return ret;
}
static int UdpClient(void)
{
int ret = 0;
int peer;
int try_count = TRY_COUNT;
char recv_data[DATA_LEN];
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
peer = socket(AF_INET, SOCK_DGRAM, 0);
if (peer < 0) {
return EXIT_CODE_ERRNO_1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
(void)memset_s(&(server_addr.sin_zero), sizeof(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
peer_addr.sin_family = AF_INET;
peer_addr.sin_addr.s_addr = inet_addr(PEER_IP);
peer_addr.sin_port = htons(PEER_PORT);
(void)memset_s(&(peer_addr.sin_zero), sizeof(peer_addr.sin_zero), 0, sizeof(peer_addr.sin_zero));
ret = bind(peer, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&peer_addr)),
sizeof(struct sockaddr));
if (ret != 0) {
return EXIT_CODE_ERRNO_2;
}
timeval tv = {1, 0};
ret = setsockopt(peer, SOL_SOCKET, SO_RCVTIMEO, const_cast<void *>(reinterpret_cast<void *>(&tv)), sizeof(timeval));
/* loop try util server is ready */
while (try_count--) {
ret = sendto(peer, PEER_MSG, strlen(PEER_MSG) + 1, 0,
const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&server_addr)),
(socklen_t)sizeof(server_addr));
if (ret == -1) {
continue;
}
ret = recvfrom(peer, recv_data, DATA_LEN, 0, nullptr, nullptr);
if (ret != -1) {
break;
}
}
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
(void)close(peer);
ret = strcmp(recv_data, SERVER_MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_4;
}
return 0;
}
static int ChildFunc(void *arg)
{
int ret = ResetNetaddr(IFNAME, PEER_IP, NETMASK, GW);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
return UdpClient();
}
static int UdpServer(void)
{
int ret = 0;
int server;
int try_count = TRY_COUNT;
char recv_data[DATA_LEN];
struct sockaddr_in server_addr;
struct sockaddr_in peer_addr;
socklen_t peer_addr_len = sizeof(struct sockaddr);
server = socket(AF_INET, SOCK_DGRAM, 0);
if (server < 0) {
return EXIT_CODE_ERRNO_1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
(void)memset_s(&(server_addr.sin_zero), sizeof(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
ret = bind(server, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&server_addr)),
sizeof(struct sockaddr));
if (ret != 0) {
return EXIT_CODE_ERRNO_2;
}
ret = recvfrom(server, recv_data, DATA_LEN, 0, reinterpret_cast<struct sockaddr *>(&peer_addr), &peer_addr_len);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = sendto(server, SERVER_MSG, strlen(SERVER_MSG) + 1, 0,
const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&peer_addr)), peer_addr_len);
if (ret < 0) {
return EXIT_CODE_ERRNO_4;
}
(void)close(server);
ret = strcmp(recv_data, PEER_MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_5;
}
return ret;
}
static void *UdpServerThread(void *arg)
{
int ret;
ret = ResetNetaddr(IFNAME, SERVER_IP, NETMASK, GW);
if (ret != 0) {
return (void *)(intptr_t)ret;
}
ret = UdpServer();
return (void *)(intptr_t)ret;
}
void ItNetContainer005(void)
{
int ret = 0;
int status;
void *tret = nullptr;
pthread_t srv;
pthread_attr_t attr;
ret = pthread_attr_init(&attr);
ASSERT_EQ(ret, 0);
ret = pthread_create(&srv, &attr, UdpServerThread, nullptr);
ASSERT_EQ(ret, 0);
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
auto pid = clone(ChildFunc, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
ret = pthread_join(srv, &tret);
ASSERT_EQ(ret, 0);
ret = pthread_attr_destroy(&attr);
ASSERT_EQ(ret, 0);
}

View File

@@ -0,0 +1,181 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <arpa/inet.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <poll.h>
#include "It_container_test.h"
static const char *SERVER_IP = "127.0.0.1";
static const int SERV_PORT = 8002;
static const char *SERVER_MSG = "Hi, I'm Tcp Server!";
static const char *PEER_MSG = "Hi, I'm Tcp Client!";
static const int DATA_LEN = 128;
static int TcpClient(void *arg)
{
int ret;
int client;
char buffer[DATA_LEN];
struct sockaddr_in server_addr;
client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client < 0) {
return EXIT_CODE_ERRNO_1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
server_addr.sin_port = htons(SERV_PORT);
(void)memset_s(&(server_addr.sin_zero), sizeof(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
ret = connect(client, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&server_addr)),
sizeof(server_addr));
if (ret < 0) {
return EXIT_CODE_ERRNO_2;
}
ret = send(client, PEER_MSG, strlen(PEER_MSG) + 1, 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = recv(client, buffer, sizeof(buffer), 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_4;
}
ret = strcmp(buffer, SERVER_MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_5;
}
(void)close(client);
return 0;
}
static int ChildFunc(void *)
{
int ret;
int server;
int status;
char *stack = nullptr;
char *stackTop = nullptr;
char buffer[DATA_LEN];
struct sockaddr_in server_addr;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server < 0) {
return EXIT_CODE_ERRNO_1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
server_addr.sin_port = htons(SERV_PORT);
(void)memset_s(&(server_addr.sin_zero), sizeof(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
ret = bind(server, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&server_addr)),
sizeof(server_addr));
if (ret < 0) {
return EXIT_CODE_ERRNO_2;
}
ret = listen(server, 1);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
int pid = clone(TcpClient, stackTop, SIGCHLD, &arg);
if (pid == -1) {
return EXIT_CODE_ERRNO_4;
}
int client = accept(server, nullptr, nullptr);
if (ret < 0) {
return EXIT_CODE_ERRNO_5;
}
ret = recv(client, buffer, sizeof(buffer), 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_6;
}
ret = strcmp(buffer, PEER_MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_7;
}
ret = send(client, SERVER_MSG, strlen(SERVER_MSG) + 1, 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_8;
}
(void)close(client);
(void)close(server);
ret = waitpid(pid, &status, 0);
if (ret != pid) {
return EXIT_CODE_ERRNO_9;
}
int exitCode = WEXITSTATUS(status);
if (exitCode != 0) {
return EXIT_CODE_ERRNO_10;
}
return 0;
}
void ItNetContainer006(void)
{
int ret = 0;
int status;
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
int pid = clone(ChildFunc, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <arpa/inet.h>
#include "It_container_test.h"
static const char *LOCALHOST = "127.0.0.1";
static const int LOCALPORT = 8003;
static const char *MSG = "Tis is UDP Test!";
static const int DATA_LEN = 128;
static int ChildFunc(void *arg)
{
int ret;
int sock;
int recv_data_len;
char recv_data[DATA_LEN];
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
return EXIT_CODE_ERRNO_1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(LOCALHOST);
addr.sin_port = htons(LOCALPORT);
(void)memset_s(&(addr.sin_zero), sizeof(addr.sin_zero), 0, sizeof(addr.sin_zero));
ret = bind(sock, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&addr)),
sizeof(struct sockaddr));
if (ret < 0) {
return EXIT_CODE_ERRNO_2;
}
ret = sendto(sock, MSG, DATA_LEN, 0, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&addr)),
(socklen_t)sizeof(addr));
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = recvfrom(sock, recv_data, DATA_LEN, 0, nullptr, nullptr);
if (ret < 0) {
return EXIT_CODE_ERRNO_4;
}
ret = strcmp(recv_data, MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_5;
}
(void)close(sock);
return 0;
}
void ItNetContainer007(void)
{
int ret = 0;
int status;
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
auto pid = clone(ChildFunc, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <poll.h>
#include "It_container_test.h"
static const int PORT = 8004;
static const char *LOCALHOST = "127.0.0.1";
static int UdpTcpBind(int *sock1, int *sock2)
{
int ret;
int udp_sock;
int tcp_sock;
udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udp_sock < 0) {
return EXIT_CODE_ERRNO_1;
}
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(LOCALHOST);
sa.sin_port = htons(PORT);
ret = bind(udp_sock, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&sa)), sizeof(sa));
if (ret != 0) {
return EXIT_CODE_ERRNO_2;
}
tcp_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (tcp_sock < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = bind(tcp_sock, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&sa)), sizeof(sa));
if (ret != 0) {
return EXIT_CODE_ERRNO_4;
}
(*sock1) = udp_sock;
(*sock2) = tcp_sock;
return 0;
}
static int ClientFunc(void *param)
{
(void)param;
int ret;
int udp_sock;
int tcp_sock;
ret = UdpTcpBind(&udp_sock, &tcp_sock);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
(void)close(udp_sock);
(void)close(tcp_sock);
return ret;
}
void ItNetContainer008(void)
{
int ret;
int status;
int udp_sock;
int tcp_sock;
ret = UdpTcpBind(&udp_sock, &tcp_sock);
ASSERT_EQ(ret, 0);
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
int pid = clone(ClientFunc, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
(void)close(udp_sock);
(void)close(tcp_sock);
}

View File

@@ -0,0 +1,260 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/route.h>
#include "It_container_test.h"
static const char *NETMASK = "255.255.255.0";
static const char *GW = "192.168.100.1";
static const char *IFNAME = "veth0";
static const char *SERVER_IP = "192.168.100.6";
static const int SERVER_PORT = 8005;
static const char *PEER_IP = "192.168.100.5";
static const char *SERVER_MSG = "===Hi, I'm Server.===";
static const char *PEER_MSG = "===Hi, I'm Peer.===";
static const int TRY_COUNT = 5;
static const int DATA_LEN = 128;
static int TryResetNetaddr(const char *ifname, const char *ip, const char *netmask, const char *gw)
{
int ret;
struct ifreq ifr;
struct rtentry rt;
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (fd < 0) {
return -1;
}
ret = strncpy_s(ifr.ifr_name, sizeof(ifr.ifr_name), ifname, IFNAMSIZ);
if (ret != EOK) {
close(fd);
return -1;
}
ifr.ifr_addr.sa_family = AF_INET;
inet_pton(AF_INET, netmask, ifr.ifr_addr.sa_data + 2); /* 2: offset */
ret = ioctl(fd, SIOCSIFNETMASK, &ifr);
if (ret == 0) {
inet_pton(AF_INET, ip, ifr.ifr_addr.sa_data + 2); /* 2: offset */
ret = ioctl(fd, SIOCSIFADDR, &ifr);
if (ret == 0) {
struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in *>(&rt.rt_gateway);
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(GW);
rt.rt_flags = RTF_GATEWAY;
ret = ioctl(fd, SIOCADDRT, &rt);
}
}
if (ret != 0) {
(void)close(fd);
return ret;
}
ret = close(fd);
return ret;
}
static int ResetNetaddr(const char *ifname, const char *ip, const char *netmask, const char *gw)
{
int ret;
int try_count = TRY_COUNT;
while (try_count--) {
ret = TryResetNetaddr(ifname, ip, netmask, gw);
if (ret == 0) {
break;
}
sleep(1);
}
return ret;
}
static int TcpClient(void)
{
int ret = 0;
int peer;
int try_count = TRY_COUNT;
char recv_data[DATA_LEN];
struct sockaddr_in server_addr;
peer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (peer < 0) {
return EXIT_CODE_ERRNO_1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
(void)memset_s(&(server_addr.sin_zero), sizeof(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
do {
sleep(1);
ret = connect(peer, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&server_addr)),
sizeof(struct sockaddr));
} while (ret !=0 && (try_count--));
if (ret < 0) {
return EXIT_CODE_ERRNO_2;
}
ret = send(peer, PEER_MSG, strlen(PEER_MSG) + 1, 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = recv(peer, recv_data, sizeof(recv_data), 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_4;
}
ret = strcmp(recv_data, SERVER_MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_5;
}
(void)close(peer);
return 0;
}
static int TcpServer(void)
{
int ret = 0;
int server;
int peer;
char recv_data[DATA_LEN];
struct sockaddr_in server_addr;
socklen_t client_addr_len = sizeof(struct sockaddr);
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server < 0) {
return EXIT_CODE_ERRNO_1;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
(void)memset_s(&(server_addr.sin_zero), sizeof(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
ret = bind(server, const_cast<struct sockaddr *>(reinterpret_cast<struct sockaddr *>(&server_addr)),
sizeof(struct sockaddr));
if (ret != 0) {
return EXIT_CODE_ERRNO_2;
}
ret = listen(server, 1);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
peer = accept(server, nullptr, nullptr);
if (peer < 0) {
return EXIT_CODE_ERRNO_4;
}
(void)close(server);
ret = recv(peer, recv_data, sizeof(recv_data), 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_5;
}
ret = strcmp(recv_data, PEER_MSG);
if (ret != 0) {
return EXIT_CODE_ERRNO_6;
}
ret = send(peer, SERVER_MSG, strlen(SERVER_MSG) + 1, 0);
if (ret < 0) {
return EXIT_CODE_ERRNO_7;
}
(void)close(peer);
return 0;
}
static void *TcpClientThread(void *arg)
{
int ret = ResetNetaddr(IFNAME, PEER_IP, NETMASK, GW);
if (ret == 0) {
ret = TcpClient();
}
return (void *)(intptr_t)ret;
}
static int ChildFunc(void *arg)
{
int ret = ret = ResetNetaddr(IFNAME, SERVER_IP, NETMASK, GW);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
return TcpServer();
}
VOID ItNetContainer009(void)
{
int ret = 0;
int status;
void *tret = nullptr;
pthread_t srv;
pthread_attr_t attr;
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
EXPECT_STRNE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
int arg = CHILD_FUNC_ARG;
int pid = clone(ChildFunc, stackTop, SIGCHLD | CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
ret = pthread_attr_init(&attr);
ASSERT_EQ(ret, 0);
ret = pthread_create(&srv, &attr, TcpClientThread, nullptr);
ASSERT_EQ(ret, 0);
ret = pthread_join(srv, &tret);
ASSERT_EQ(ret, 0);
ret = pthread_attr_destroy(&attr);
ASSERT_EQ(ret, 0);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "sys/resource.h"
#include "sys/wait.h"
#include "pthread.h"
#include "sched.h"
#include "It_container_test.h"
const int MAX_PID_RANGE = 100000;
const int SLEEP_TIME_US = 1000;
const int LOOP_NUM = 100;
static int ChildFunc(void *arg)
{
usleep(SLEEP_TIME_US);
exit(EXIT_CODE_ERRNO_5);
}
static int GroupProcess(void *arg)
{
(void)arg;
int ret;
int status = 0;
for (int i = 0; i < LOOP_NUM; i++) {
int argTmp = CHILD_FUNC_ARG;
auto pid = CloneWrapper(ChildFunc, CLONE_NEWNET, &argTmp);
if (pid == -1) {
return EXIT_CODE_ERRNO_1;
}
ret = waitpid(pid, &status, 0);
status = WEXITSTATUS(status);
if (status != EXIT_CODE_ERRNO_5) {
return EXIT_CODE_ERRNO_2;
}
}
exit(EXIT_CODE_ERRNO_5);
}
void ItNetContainer010(void)
{
int ret;
int status = 0;
int arg = CHILD_FUNC_ARG;
auto pid = CloneWrapper(GroupProcess, CLONE_NEWNET, &arg);
ASSERT_NE(pid, -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
status = WEXITSTATUS(status);
ASSERT_EQ(status, EXIT_CODE_ERRNO_5);
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdio>
#include "It_container_test.h"
static int const configLen = 16;
static const int MAX_CONTAINER = 10;
static const int g_buffSize = 512;
static const int g_arryLen = 4;
static const int g_readLen = 254;
static int childFunc(void *arg)
{
(void)arg;
sleep(2); /* 2: delay 2s */
return 0;
}
void ItNetContainer011(void)
{
std::string path = "/proc/sys/user/max_net_container";
char *array[g_arryLen] = { nullptr };
char buf[g_buffSize] = { 0 };
int ret = ReadFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
GetLine(buf, g_arryLen, g_readLen, array);
int value = atoi(array[1] + strlen("limit: "));
ASSERT_EQ(value, MAX_CONTAINER);
int usedCount = atoi(array[2] + strlen("count: "));
(void)memset_s(buf, configLen, 0, configLen);
ret = sprintf_s(buf, configLen, "%d", usedCount + 1);
ASSERT_GT(ret, 0);
ret = WriteFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid1 = clone(childFunc, stackTop, CLONE_NEWNET, NULL);
ASSERT_NE(pid1, -1);
auto pid2 = clone(childFunc, stackTop, CLONE_NEWNET, NULL);
ASSERT_EQ(pid2, -1);
ret = waitpid(pid1, NULL, 0);
ASSERT_EQ(ret, pid1);
(void)memset_s(buf, configLen, 0, configLen);
ret = sprintf_s(buf, configLen, "%d", value);
ASSERT_GT(ret, 0);
ret = WriteFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
(void)memset_s(buf, configLen, 0, configLen);
ret = ReadFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
GetLine(buf, g_arryLen, g_readLen, array);
value = atoi(array[1] + strlen("limit: "));
ASSERT_EQ(value, MAX_CONTAINER);
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstdio>
#include "It_container_test.h"
static int const configLen = 16;
static const int MAX_CONTAINER = 10;
static const int g_buffSize = 512;
static const int g_arryLen = 4;
static const int g_readLen = 254;
static int childFunc(void *arg)
{
(void)arg;
int ret = unshare(CLONE_NEWNET);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
return 0;
}
void ItNetContainer012(void)
{
std::string path = "/proc/sys/user/max_net_container";
char *array[g_arryLen] = { nullptr };
char buf[g_buffSize] = { 0 };
int status = 0;
int ret = ReadFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
GetLine(buf, g_arryLen, g_readLen, array);
int value = atoi(array[1] + strlen("limit: "));
ASSERT_EQ(value, MAX_CONTAINER);
int usedCount = atoi(array[2] + strlen("count: "));
(void)memset_s(buf, configLen, 0, configLen);
ret = sprintf_s(buf, configLen, "%d", usedCount + 1);
ASSERT_GT(ret, 0);
ret = WriteFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid1 = clone(childFunc, stackTop, CLONE_NEWNET, NULL);
ASSERT_NE(pid1, -1);
ret = waitpid(pid1, &status, 0);
ASSERT_EQ(ret, pid1);
ret = WIFEXITED(status);
ASSERT_NE(ret, 0);
ret = WEXITSTATUS(status);
ASSERT_EQ(ret, EXIT_CODE_ERRNO_1);
(void)memset_s(buf, configLen, 0, configLen);
ret = sprintf_s(buf, configLen, "%d", value);
ASSERT_GT(ret, 0);
ret = WriteFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
(void)memset_s(buf, configLen, 0, configLen);
ret = ReadFile(path.c_str(), buf);
ASSERT_NE(ret, -1);
GetLine(buf, g_arryLen, g_readLen, array);
value = atoi(array[1] + strlen("limit: "));
ASSERT_EQ(value, MAX_CONTAINER);
}

View File

@@ -165,6 +165,18 @@ HWTEST_F(ProcessFsTest, ItProcessFs010, TestSize.Level0)
ItProcessFs010();
}
/**
* @tc.name: Process_fs_Test_011
* @tc.desc: Process mount directory test
* @tc.type: FUNC
* @tc.require: issueI6E2LG
* @tc.author:
*/
HWTEST_F(ProcessFsTest, ItProcessFs011, TestSize.Level0)
{
ItProcessFs011();
}
/**
* @tc.name: Process_fs_Test_012
* @tc.desc: Process mount directory test

View File

@@ -56,7 +56,7 @@ void ItProcessPlimitsIpc009(void)
ASSERT_EQ(ret, 0);
ret = ReadFile("/proc/plimits/test/ipc.shm_limit", buf);
ASSERT_STREQ(buf, "104857600\n");
ASSERT_STREQ(buf, "4294967295\n");
shmid = shmget(IPC_PRIVATE, PAGE_SIZE, acessMode | IPC_CREAT);
ASSERT_NE(shmid, -1);

View File

@@ -92,7 +92,6 @@ void ItProcessPlimitsIpc010(void)
ret = shmctl(shmid, IPC_RMID, nullptr);
ASSERT_NE(ret, -1);
shmctl(shmid_1, IPC_RMID, nullptr);
shmctl(shmid, IPC_RMID, nullptr);
ret = rmdir(subPlimitsPath.c_str());
ASSERT_EQ(ret, 0);