This commit is contained in:
Ze Gan 2024-03-25 13:39:21 -07:00 committed by GitHub
commit 591e0d42eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 947 additions and 70 deletions

View File

@ -47,6 +47,7 @@ DOCKER_CTL_SCRIPT="$DOCKER_CTL_DIR/docker.sh"
FILESYSTEM_ROOT_USR="$FILESYSTEM_ROOT/usr"
FILESYSTEM_ROOT_USR_LIB="$FILESYSTEM_ROOT/usr/lib/"
FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM="$FILESYSTEM_ROOT_USR_LIB/systemd/system"
FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK="$FILESYSTEM_ROOT_USR_LIB/systemd/network"
FILESYSTEM_ROOT_USR_SHARE="$FILESYSTEM_ROOT_USR/share"
FILESYSTEM_ROOT_USR_SHARE_SONIC="$FILESYSTEM_ROOT_USR_SHARE/sonic"
FILESYSTEM_ROOT_USR_SHARE_SONIC_SCRIPTS="$FILESYSTEM_ROOT_USR_SHARE_SONIC/scripts"
@ -637,6 +638,34 @@ sudo cp $IMAGE_CONFIGS/config-chassisdb/config-chassisdb $FILESYSTEM_ROOT/usr/bi
echo "config-chassisdb.service" | sudo tee -a $GENERATED_SERVICE_FILE
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable config-chassisdb.service
# Copy midplane network service file for smart switch
sudo cp $IMAGE_CONFIGS/midplane-network/bridge-midplane.netdev $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK/bridge-midplane.netdev
sudo cp $IMAGE_CONFIGS/midplane-network/bridge-midplane.network $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK/bridge-midplane.network
sudo cp $IMAGE_CONFIGS/midplane-network/dummy-midplane.netdev $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK/dummy-midplane.netdev
sudo cp $IMAGE_CONFIGS/midplane-network/dummy-midplane.network $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK/dummy-midplane.network
sudo cp $IMAGE_CONFIGS/midplane-network/midplane-network-npu.network $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK/midplane-network-npu.network
sudo cp $IMAGE_CONFIGS/midplane-network/midplane-network-dpu.network $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_NETWORK/midplane-network-dpu.network
sudo cp $IMAGE_CONFIGS/midplane-network/midplane-network-npu.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM/midplane-network-npu.service
sudo cp $IMAGE_CONFIGS/midplane-network/midplane-network-dpu.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM/midplane-network-dpu.service
# Disable smart switch unit by default, these units will be controlled by systemd-sonic-generator
sudo ln -s /dev/null $FILESYSTEM_ROOT/etc/systemd/network/bridge-midplane.netdev
sudo ln -s /dev/null $FILESYSTEM_ROOT/etc/systemd/network/bridge-midplane.network
sudo ln -s /dev/null $FILESYSTEM_ROOT/etc/systemd/network/dummy-midplane.netdev
sudo ln -s /dev/null $FILESYSTEM_ROOT/etc/systemd/network/dummy-midplane.network
sudo ln -s /dev/null $FILESYSTEM_ROOT/etc/systemd/network/midplane-network-npu.network
sudo ln -s /dev/null $FILESYSTEM_ROOT/etc/systemd/network/midplane-network-dpu.network
echo "midplane-network-npu.service" | sudo tee -a $GENERATED_SERVICE_FILE
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable midplane-network-npu.service
echo "midplane-network-dpu.service" | sudo tee -a $GENERATED_SERVICE_FILE
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable midplane-network-dpu.service
# According to the issue: https://github.com/systemd/systemd/issues/19106, To disable ManageForeignRoutingPolicyRules to avoid the ip rules being deleted by systemd-networkd
sudo sed -i 's/#ManageForeignRoutingPolicyRules=yes/ManageForeignRoutingPolicyRules=no/g' $FILESYSTEM_ROOT/etc/systemd/networkd.conf
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl enable systemd-networkd
sudo LANG=C chroot $FILESYSTEM_ROOT systemctl disable systemd-networkd-wait-online.service
# Copy backend-acl script and service file
sudo cp $IMAGE_CONFIGS/backend_acl/backend-acl.service $FILESYSTEM_ROOT_USR_LIB_SYSTEMD_SYSTEM/backend-acl.service
sudo cp $IMAGE_CONFIGS/backend_acl/backend_acl.py $FILESYSTEM_ROOT/usr/bin/backend_acl.py

View File

@ -0,0 +1,5 @@
# Bridge interface for midplane network
[NetDev]
Name=bridge-midplane
Kind=bridge

View File

@ -0,0 +1,8 @@
# Network configuration for bridge midplane
[Match]
Name=bridge-midplane
[Network]
Address=169.254.200.254/24
LinkLocalAddressing=no

View File

@ -0,0 +1,5 @@
# Dummy interface for midplane network
[NetDev]
Name=dummy-midplane
Kind=dummy

View File

@ -0,0 +1,9 @@
# The systemd-networkd requires that the bridge interface(bridge-midplane) has at least one member interface, otherwise the IP address will not be configured.
# This dummy interface will be added into the bridge-midplane as a member to guarantee the IP address configuration correctly.
# Refer: https://github.com/systemd/systemd/issues/9252#issuecomment-771540028
[Match]
Name=dummy-midplane
[Network]
Bridge=bridge-midplane

View File

@ -0,0 +1,5 @@
[Match]
Name=eth0-midplane
[Network]
DHCP=yes

View File

@ -0,0 +1,15 @@
# Oneshot midplane network service
[Unit]
Description=Midplane network service
Requires=systemd-networkd.service
After=systemd-networkd.service
Before=database.service
[Service]
Type=oneshot
User=root
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online -i eth0-midplane --timeout=600
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,5 @@
[Match]
Name=dpu*
[Network]
Bridge=bridge-midplane

View File

@ -0,0 +1,14 @@
# Oneshot midplane network service
[Unit]
Description=Midplane network service
Requires=systemd-networkd.service
After=systemd-networkd.service
[Service]
Type=oneshot
User=root
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online -i bridge-midplane
[Install]
WantedBy=multi-user.target

View File

@ -3,14 +3,14 @@ CFLAGS += -std=gnu99 -D_GNU_SOURCE
CXX=g++
CXXFLAGS += -std=c++11 -D_GNU_SOURCE
LDFLAGS += -lpthread -lboost_filesystem -lboost_system -lgtest
LDFLAGS += -lpthread -lboost_filesystem -lboost_system -lgtest -ljson-c
BINARY = systemd-sonic-generator
$(BINARY): systemd-sonic-generator.c
rm -f ./systemd-sonic-generator
$(CC) $(CFLAGS) -o $@ $^
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
install: $(BINARY)
mkdir -p $(DESTDIR)

View File

@ -9,9 +9,11 @@
#include <mutex>
#include <string>
#include <sys/stat.h>
#include <linux/limits.h>
#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <nlohmann/json.hpp>
#include "systemd-sonic-generator.h"
namespace fs = boost::filesystem;
@ -19,7 +21,7 @@ namespace fs = boost::filesystem;
namespace SSGTest {
#define IS_MULTI_ASIC(x) ((x) > 1)
#define IS_SINGLE_ASIC(x) ((x) <= 1)
#define NUM_UNIT_FILES 6
#define NUM_UNIT_FILES 9
/*
* This test class uses following directory hierarchy for input and output
@ -40,27 +42,36 @@ namespace SSGTest {
*/
const std::string TEST_ROOT_DIR = "tests/ssg-test/";
const std::string TEST_UNIT_FILE_PREFIX = TEST_ROOT_DIR + "systemd/";
const std::string TEST_LIB_NETWORK = TEST_UNIT_FILE_PREFIX + "network/";
const std::string TEST_ASIC_CONF_FORMAT = TEST_ROOT_DIR + "%s/asic.conf";
const std::string TEST_PLATFORM_CONF_FORMAT = TEST_ROOT_DIR + "%s/platform.json";
const std::string TEST_MACHINE_CONF = TEST_ROOT_DIR + "machine.conf";
const std::string TEST_PLATFORM_DIR = TEST_ROOT_DIR + "test_platform/";
const std::string TEST_ASIC_CONF = TEST_PLATFORM_DIR + "asic.conf";
const std::string TEST_PLATFORM_CONF = TEST_PLATFORM_DIR + "platform.json";
const std::string TEST_OUTPUT_DIR = TEST_ROOT_DIR + "generator/";
const std::string TEST_ETC_NETWORK = TEST_OUTPUT_DIR + "network/";
const std::string TEST_CONFIG_FILE = TEST_ROOT_DIR + "generated_services.conf";
const std::string TEST_UNIT_FILES = "tests/testfiles/";
/* Input data for generated_services.conf */
const std::vector<std::string> generated_services = {
"multi_inst_a.service", /* Single instance of a multi asic service a */
"multi_inst_a@.service", /* Multi-instance of a multi asic service a */
"multi_inst_b@.service", /* Multi-instance of a multi asic service b */
"single_inst.service", /* A single instance service */
"test.service", /* A single instance test service
to test dependency creation */
"test.timer", /* A timer service */
"multi_inst_a.service", /* Single instance of a multi asic service a */
"multi_inst_a@.service", /* Multi-instance of a multi asic service a */
"multi_inst_b@.service", /* Multi-instance of a multi asic service b */
"single_inst.service", /* A single instance service */
"test.service", /* A single instance test service
to test dependency creation */
"test.timer", /* A timer service */
"midplane-network-npu.service", /* A midplane network service for smart switch NPU*/
"midplane-network-dpu.service", /* A midplane network service for smart switch DPU*/
"database.service", /* A database service*/
"database@.service", /* A database service for multi instances */
};
static std::mutex g_ssg_test_mutex;
@ -120,8 +131,13 @@ class SsgFunctionTest : public SystemdSonicGeneratorFixture {
try {
fs::path current(file->path());
if(!fs::is_directory(current)) {
std::string ext = boost::filesystem::extension(current);
fs::path dest_path = dest_dir;
if (ext == ".netdev" || ext == ".network" || ext == ".link") {
dest_path = dest_path / "network";
}
/* Copy file */
fs::copy_file( current, dest_dir / current.filename());
fs::copy_file( current, dest_path / current.filename());
}
}
catch(fs::filesystem_error const & e) {
@ -142,6 +158,10 @@ class SsgFunctionTest : public SystemdSonicGeneratorFixture {
fs::create_directories(path);
path = fs::path(TEST_PLATFORM_DIR.c_str());
fs::create_directories(path);
path = fs::path(TEST_LIB_NETWORK.c_str());
fs::create_directories(path);
path = fs::path(TEST_ETC_NETWORK.c_str());
fs::create_directories(path);
fp = fopen(TEST_MACHINE_CONF.c_str(), "w");
ASSERT_NE(fp, nullptr);
fputs("onie_platform=test_platform", fp);
@ -163,6 +183,15 @@ class SsgFunctionTest : public SystemdSonicGeneratorFixture {
private:
};
struct SsgMainConfig {
int num_asics = 0;
bool is_smart_switch_npu = false;
bool is_smart_switch_dpu = false;
int num_dpus = 0;
};
/*
* class SsgMainTest
* Implements functions to test ssg_main routine.
@ -228,10 +257,10 @@ class SsgMainTest : public SsgFunctionTest {
void validate_output_unit_files(std::vector<std::string> strs,
std::string target,
bool expected_result,
int num_asics) {
int num_instances) {
for (std::string str : strs) {
bool finished = false;
for (int i = 0 ; i < num_asics && !finished; ++i) {
for (int i = 0 ; i < num_instances && !finished; ++i) {
auto str_t = str;
if (is_multi_instance(str)) {
/* insert instance id in string */
@ -241,7 +270,10 @@ class SsgMainTest : public SsgFunctionTest {
finished = true;
}
fs::path path{TEST_OUTPUT_DIR + target + "/" + str_t};
EXPECT_EQ(fs::exists(path), expected_result)
char resolved_path[PATH_MAX];
realpath(path.c_str(), resolved_path);
bool exist = fs::exists(path) && strcmp(resolved_path, "/dev/null") != 0;
EXPECT_EQ(exist, expected_result)
<< "Failed validation: " << path;
}
}
@ -250,7 +282,7 @@ class SsgMainTest : public SsgFunctionTest {
/*
* This function validates the generated dependencies in a Unit File.
*/
void validate_depedency_in_unit_file(int num_asics) {
void validate_depedency_in_unit_file(const SsgMainConfig &cfg) {
std::string test_service = "test.service";
/* Validate Unit file dependency creation for multi instance
@ -258,53 +290,83 @@ class SsgMainTest : public SsgFunctionTest {
* system but not present for single asic system.
*/
validate_output_dependency_list(multi_asic_dependency_list,
test_service, IS_MULTI_ASIC(num_asics), num_asics);
test_service, IS_MULTI_ASIC(cfg.num_asics), cfg.num_asics);
/* Validate Unit file dependency creation for single instance
* services. These entries should not be present for multi asic
* system but present for single asic system.
/* This section handles a tricky scenario.
* When the number of DPUs (Data Processing Units) is greater than 0,
* the dependency list will be split. Otherwise, it remains in one line.
* Despite the split, the final result remains equivalent.
*/
validate_output_dependency_list(single_asic_dependency_list,
test_service, IS_SINGLE_ASIC(num_asics), num_asics);
if (cfg.num_dpus > 0) {
/* Validate Unit file dependency creation for single instance
* services. These entries should not be present for multi asic
* system but present for single asic system.
*/
validate_output_dependency_list(single_asic_dependency_list_split,
test_service, IS_SINGLE_ASIC(cfg.num_asics), cfg.num_asics);
validate_output_dependency_list(npu_dependency_list,
"midplane-network-npu.service", true, cfg.num_dpus);
} else {
/* Validate Unit file dependency creation for single instance
* services. These entries should not be present for multi asic
* system but present for single asic system.
*/
validate_output_dependency_list(single_asic_dependency_list,
test_service, IS_SINGLE_ASIC(cfg.num_asics), cfg.num_asics);
}
/* Validate Unit file dependency creation for single instance
* common services. These entries should not be present for multi
* and single asic system.
*/
validate_output_dependency_list(common_dependency_list,
test_service, true, num_asics);
test_service, true, cfg.num_asics);
}
/*
* This function validates the list of generated Service Unit Files.
*/
void validate_service_file_generated_list(int num_asics) {
void validate_service_file_generated_list(const SsgMainConfig &cfg) {
std::string test_target = "multi-user.target.wants";
validate_output_unit_files(multi_asic_service_list,
test_target, IS_MULTI_ASIC(num_asics), num_asics);
test_target, IS_MULTI_ASIC(cfg.num_asics), cfg.num_asics);
validate_output_unit_files(single_asic_service_list,
test_target, IS_SINGLE_ASIC(num_asics), num_asics);
test_target, IS_SINGLE_ASIC(cfg.num_asics), cfg.num_asics);
validate_output_unit_files(common_service_list,
test_target, true, num_asics);
test_target, true, cfg.num_asics);
validate_output_unit_files(npu_service_list,
test_target, cfg.is_smart_switch_npu, cfg.num_dpus);
validate_output_unit_files(npu_network_service_list,
"network", cfg.is_smart_switch_npu, cfg.num_dpus);
validate_output_unit_files(dpu_service_list,
test_target, cfg.is_smart_switch_dpu, cfg.num_dpus);
validate_output_unit_files(dpu_network_service_list,
"network", cfg.is_smart_switch_dpu, cfg.num_dpus);
}
/* ssg_main test routine.
* input: num_asics number of asics
*/
void ssg_main_test(int num_asics) {
void ssg_main_test(const SsgMainConfig &cfg) {
FILE* fp;
std::vector<char*> argv_;
std::vector<std::string> arguments = {
"ssg_main",
TEST_OUTPUT_DIR.c_str()
};
std::string num_asic_str = "NUM_ASIC=" + std::to_string(num_asics);
std::string num_asic_str = "NUM_ASIC=" + std::to_string(cfg.num_asics);
std::string unit_file_path = fs::current_path().string() + "/" +TEST_UNIT_FILE_PREFIX;
g_unit_file_prefix = unit_file_path.c_str();
g_config_file = TEST_CONFIG_FILE.c_str();
g_machine_config_file = TEST_MACHINE_CONF.c_str();
g_asic_conf_format = TEST_ASIC_CONF_FORMAT.c_str();
g_platform_file_format = TEST_PLATFORM_CONF_FORMAT.c_str();
std::string lib_systemd = fs::current_path().string() + "/" + TEST_UNIT_FILE_PREFIX;
g_lib_systemd = lib_systemd.c_str();
std::string etc_systemd = fs::current_path().string() + "/" + TEST_OUTPUT_DIR;
g_etc_systemd = etc_systemd.c_str();
/* Set NUM_ASIC value in asic.conf */
fp = fopen(TEST_ASIC_CONF.c_str(), "w");
@ -312,6 +374,29 @@ class SsgMainTest : public SsgFunctionTest {
fputs(num_asic_str.c_str(), fp);
fclose(fp);
/* Set platform file for smart switch */
if (cfg.is_smart_switch_dpu || cfg.is_smart_switch_npu) {
nlohmann::json platform_config;
if (cfg.is_smart_switch_dpu) {
ASSERT_EQ(cfg.num_dpus, 0);
ASSERT_EQ(cfg.is_smart_switch_npu, false);
platform_config["DPU"] = nlohmann::json::object();
}
else if (cfg.is_smart_switch_npu) {
ASSERT_EQ(cfg.is_smart_switch_dpu, false);
nlohmann::json dpus;
for (int i = 0; i < cfg.num_dpus; i++) {
dpus["dpu" + std::to_string(i)] = nlohmann::json::object();
}
platform_config["DPUS"] = dpus;
}
fp = fopen(TEST_PLATFORM_CONF.c_str(), "w");
ASSERT_NE(fp, nullptr);
fputs(platform_config.dump().c_str(), fp);
fclose(fp);
}
/* Create argv list for ssg_main. */
for (const auto& arg : arguments) {
argv_.push_back((char*)arg.data());
@ -322,15 +407,22 @@ class SsgMainTest : public SsgFunctionTest {
EXPECT_EQ(ssg_main(argv_.size(), argv_.data()), 0);
/* Validate systemd service template creation. */
validate_service_file_generated_list(num_asics);
validate_service_file_generated_list(cfg);
/* Validate Test Unit file for dependency creation. */
validate_depedency_in_unit_file(num_asics);
validate_depedency_in_unit_file(cfg);
}
/* Save global variables before running tests */
virtual void SetUp() {
SsgFunctionTest::SetUp();
// Create /dev/null symlink for simulation disabled service
std::vector<std::string> disabled_service;
disabled_service.insert(disabled_service.end(), npu_network_service_list.begin(), npu_network_service_list.end());
disabled_service.insert(disabled_service.end(), dpu_network_service_list.begin(), dpu_network_service_list.end());
for (const auto &service : disabled_service) {
fs::create_symlink("/dev/null", TEST_ETC_NETWORK + service);
}
}
/* Restore global vars */
@ -343,8 +435,14 @@ class SsgMainTest : public SsgFunctionTest {
static const std::vector<std::string> single_asic_service_list;
static const std::vector<std::string> multi_asic_service_list;
static const std::vector<std::string> common_service_list;
static const std::vector<std::string> npu_service_list;
static const std::vector<std::string> npu_network_service_list;
static const std::vector<std::string> dpu_service_list;
static const std::vector<std::string> dpu_network_service_list;
static const std::vector<std::string> single_asic_dependency_list;
static const std::vector<std::string> single_asic_dependency_list_split;
static const std::vector<std::string> multi_asic_dependency_list;
static const std::vector<std::string> npu_dependency_list;
static const std::vector<std::string> common_dependency_list;
};
@ -368,6 +466,7 @@ const std::vector<std::string>
SsgMainTest::multi_asic_service_list = {
"multi_inst_a@%1%.service",
"multi_inst_b@%1%.service",
"database@%1%.service",
};
/* Common Systemd service Unit file list for single and multi asic system. */
@ -376,7 +475,36 @@ SsgMainTest::common_service_list = {
"multi_inst_a.service",
"single_inst.service",
"test.service",
"database.service",
};
/* Systemd service Unit file list for Smart Switch NPU. */
const std::vector<std::string>
SsgMainTest::npu_service_list = {
"database@dpu%1%.service",
"midplane-network-npu.service",
};
/* Systemd service Unit file list for Smart Switch NPU. */
const std::vector<std::string>
SsgMainTest::npu_network_service_list = {
"bridge-midplane.netdev",
"bridge-midplane.network",
"dummy-midplane.netdev",
"dummy-midplane.network",
"midplane-network-npu.network",
};
/* Systemd service Unit file list for Smart Switch DPU. */
const std::vector<std::string>
SsgMainTest::dpu_service_list = {
"midplane-network-dpu.service",
};
/* Systemd service Unit file list for Smart Switch DPU. */
const std::vector<std::string>
SsgMainTest::dpu_network_service_list = {
"midplane-network-dpu.network",
};
/*
@ -398,6 +526,13 @@ SsgMainTest::single_asic_dependency_list = {
"After=multi_inst_a.service multi_inst_b.service",
};
/* Systemd service Unit file dependency entries for Single asic system. */
const std::vector<std::string>
SsgMainTest::single_asic_dependency_list_split = {
"After=multi_inst_a.service",
"After=multi_inst_b.service",
};
/* Systemd service Unit file dependency entries for multi asic system. */
const std::vector<std::string>
SsgMainTest::multi_asic_dependency_list = {
@ -413,6 +548,11 @@ SsgMainTest::common_dependency_list = {
"Before=single_inst.service",
};
const std::vector<std::string>
SsgMainTest::npu_dependency_list = {
"Before=database@dpu%1%.service",
};
/* Test get functions for global vasr*/
TEST_F(SystemdSonicGeneratorFixture, get_global_vars) {
EXPECT_EQ(g_unit_file_prefix, nullptr);
@ -460,7 +600,7 @@ TEST_F(SsgFunctionTest, insert_instance_number) {
char input[] = "test@.service";
for (int i = 0; i <= 100; ++i) {
std::string out = "test@" + std::to_string(i) + ".service";
char* ret = insert_instance_number(input, i);
char* ret = insert_instance_number(input, i, "");
ASSERT_NE(ret, nullptr);
EXPECT_STREQ(ret, out.c_str());
}
@ -495,13 +635,30 @@ TEST_F(SsgFunctionTest, get_num_of_asic) {
/* TEST get_unit_files()*/
TEST_F(SsgFunctionTest, get_unit_files) {
g_unit_file_prefix = TEST_UNIT_FILE_PREFIX.c_str();
g_lib_systemd = TEST_UNIT_FILE_PREFIX.c_str();
g_etc_systemd = TEST_OUTPUT_DIR.c_str();
g_config_file = TEST_CONFIG_FILE.c_str();
char* unit_files[NUM_UNIT_FILES];
char* unit_files[NUM_UNIT_FILES] = { NULL };
int num_unit_files = get_unit_files(unit_files);
EXPECT_EQ(num_unit_files, NUM_UNIT_FILES);
for (std::string service : generated_services) {
// Exclude the midplane-network-{npu/dpu}.service which is only used for smart switch
auto non_smart_switch_generated_services = generated_services;
non_smart_switch_generated_services.erase(
std::remove(non_smart_switch_generated_services.begin(),
non_smart_switch_generated_services.end(),
"midplane-network-npu.service"),
non_smart_switch_generated_services.end());
non_smart_switch_generated_services.erase(
std::remove(non_smart_switch_generated_services.begin(),
non_smart_switch_generated_services.end(),
"midplane-network-dpu.service"),
non_smart_switch_generated_services.end());
EXPECT_EQ(num_unit_files, non_smart_switch_generated_services.size());
for (std::string service : non_smart_switch_generated_services) {
bool found = false;
for (auto& unit_file : unit_files) {
if (unit_file == NULL) {
continue;
}
if(unit_file == service) {
found = true;
break;
@ -530,18 +687,49 @@ TEST_F(SsgMainTest, ssg_main_argv) {
/* TEST ssg_main() single asic */
TEST_F(SsgMainTest, ssg_main_single_npu) {
ssg_main_test(1);
SsgMainConfig cfg;
cfg.num_asics = 1;
ssg_main_test(cfg);
}
/* TEST ssg_main() multi(10) asic */
TEST_F(SsgMainTest, ssg_main_10_npu) {
ssg_main_test(10);
SsgMainConfig cfg;
cfg.num_asics = 10;
ssg_main_test(cfg);
}
/* TEST ssg_main() multi(40) asic */
TEST_F(SsgMainTest, ssg_main_40_npu) {
ssg_main_test(40);
SsgMainConfig cfg;
cfg.num_asics = 40;
ssg_main_test(cfg);
}
TEST_F(SsgMainTest, ssg_main_smart_switch_npu) {
SsgMainConfig cfg;
cfg.num_asics = 1;
cfg.is_smart_switch_npu = true;
cfg.num_dpus = 8;
ssg_main_test(cfg);
}
TEST_F(SsgMainTest, ssg_main_smart_switch_dpu) {
SsgMainConfig cfg;
cfg.num_asics = 1;
cfg.is_smart_switch_dpu = true;
ssg_main_test(cfg);
}
TEST_F(SsgMainTest, ssg_main_smart_switch_double_execution) {
SsgMainConfig cfg;
cfg.num_asics = 1;
cfg.is_smart_switch_npu = true;
cfg.num_dpus = 8;
ssg_main_test(cfg);
ssg_main_test(cfg);
}
}
int main(int argc, char** argv) {

View File

@ -8,16 +8,35 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <json-c/json.h>
#define MAX_NUM_TARGETS 48
#define MAX_NUM_INSTALL_LINES 48
#define MAX_NUM_UNITS 128
#define MAX_BUF_SIZE 512
#define MAX_PLATFORM_NAME_LEN 64
const char* LIB_SYSTEMD = "/usr/lib/systemd";
const char* ETC_SYSTEMD = "/etc/systemd";
const char* UNIT_FILE_PREFIX = "/usr/lib/systemd/system/";
const char* CONFIG_FILE = "/etc/sonic/generated_services.conf";
const char* MACHINE_CONF_FILE = "/host/machine.conf";
const char* ASIC_CONF_FORMAT = "/usr/share/sonic/device/%s/asic.conf";
const char* PLATFORM_FILE_FORMAT = "/usr/share/sonic/device/%s/platform.json";
const char* DPU_PREFIX = "dpu";
const char* g_lib_systemd = NULL;
const char* get_lib_systemd () {
return (g_lib_systemd) ? g_lib_systemd : LIB_SYSTEMD;
}
const char* g_etc_systemd = NULL;
const char* get_etc_systemd () {
return (g_etc_systemd) ? g_etc_systemd : ETC_SYSTEMD;
}
const char* g_unit_file_prefix = NULL;
const char* get_unit_file_prefix() {
@ -39,9 +58,64 @@ const char* get_asic_conf_format() {
return (g_asic_conf_format) ? g_asic_conf_format : ASIC_CONF_FORMAT;
}
const char* g_platform_file_format = NULL;
const char* get_platform_file_format() {
return (g_platform_file_format) ? g_platform_file_format : PLATFORM_FILE_FORMAT;
}
static int num_asics;
static char** multi_instance_services;
static int num_multi_inst;
static bool smart_switch_npu;
static bool smart_switch_dpu;
static bool smart_switch;
static size_t num_dpus;
static char* platform = NULL;
static struct json_object *platform_info = NULL;
#ifdef _SSG_UNITTEST
/**
* @brief Cleans up the cache by resetting cache pointers.
*/
void clean_up_cache() {
platform = NULL;
platform_info = NULL;
}
#endif
/**
* Sets the value of a pointer to an invalid memory address.
*
* @param pointer A pointer to a pointer variable.
*/
void set_invalid_pointer(void **pointer) {
*pointer = (void *)-1;
}
/**
* @brief Checks if a pointer is valid.
*
* This function checks if a pointer is valid by verifying that it is not NULL and not equal to (void *)-1.
*
* @param pointer The pointer to be checked.
* @return true if the pointer is valid, false otherwise.
*/
bool is_valid_pointer(void *pointer) {
return pointer != NULL && pointer != (void *)-1;
}
/**
* Checks if a pointer is initialized.
*
* @param pointer The pointer to check.
* @return true if the pointer is not NULL, false otherwise.
*/
bool is_initialized_pointer(void *pointer) {
return pointer != NULL;
}
void strip_trailing_newline(char* str) {
/***
@ -54,6 +128,22 @@ void strip_trailing_newline(char* str) {
}
/**
* Checks if the given path is "/dev/null".
*
* @param path The path to check.
* @return true if the path is "/dev/null", false otherwise.
*/
static bool is_devnull(const char* path)
{
char resolved_path[PATH_MAX];
if (realpath(path, resolved_path) == NULL) {
return false;
}
return strcmp(resolved_path, "/dev/null") == 0;
}
static int get_target_lines(char* unit_file, char* target_lines[]) {
/***
Gets installation information for a given unit file
@ -128,6 +218,48 @@ static bool is_multi_instance_service(char *service_name){
}
/**
* Checks if a service is a multi-instance service for DPU.
*
* @param service_name The name of the service to check.
* @return true if the service is a multi-instance service for DPU, false otherwise.
*/
static bool is_multi_instance_service_for_dpu(const char *service_name) {
if (!smart_switch_npu) {
return false;
}
const static char* multi_instance_services_for_dpu[] = {"database"};
char *tmp_service_name = strdup(service_name);
if (tmp_service_name == NULL) {
fprintf(stderr, "Error: Failed to allocate memory for tmp_service_name\n");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < sizeof(multi_instance_services_for_dpu) /
sizeof(multi_instance_services_for_dpu[0]);
i++) {
char* saveptr;
char* token = strtok_r(tmp_service_name, "@", &saveptr);
if (token) {
if (strstr(token, ".service") != NULL) {
/* If we are here, service_name did not have '@' delimiter but
* contains '.service' */
token = strtok_r(tmp_service_name, ".", &saveptr);
}
}
if (strcmp(tmp_service_name, multi_instance_services_for_dpu[i]) == 0) {
free(tmp_service_name);
return true;
}
}
free(tmp_service_name);
return false;
}
static int get_install_targets_from_line(char* target_string, char* install_type, char* targets[], int existing_targets) {
/***
Helper fuction for get_install_targets
@ -231,12 +363,18 @@ static void replace_multi_inst_dep(char *src) {
service_name = strdup(word);
service_name = strtok_r(service_name, ".", &save_ptr2);
type = strtok_r(NULL, "\n", &save_ptr2);
if (is_multi_instance_service(word)) {
if (num_asics > 1 && is_multi_instance_service(word)) {
for(i = 0; i < num_asics; i++) {
snprintf(buf, MAX_BUF_SIZE, "%s=%s@%d.%s\n",
token, service_name, i, type);
fputs(buf,fp_tmp);
}
} else if (smart_switch_npu && is_multi_instance_service_for_dpu(word)) {
for(i = 0; i < num_dpus; i++) {
snprintf(buf, MAX_BUF_SIZE, "%s=%s@%s%d.%s\n",
token, service_name, DPU_PREFIX, i, type);
fputs(buf,fp_tmp);
}
} else {
snprintf(buf, MAX_BUF_SIZE,"%s=%s.%s\n",token, service_name, type);
fputs(buf, fp_tmp);
@ -283,7 +421,8 @@ int get_install_targets(char* unit_file, char* targets[]) {
dot_ptr = strchr(instance_name, '.');
*dot_ptr = '\0';
if((num_asics > 1) && (!is_multi_instance_service(instance_name))) {
if(((num_asics > 1) && (!is_multi_instance_service(instance_name)))
|| ((num_dpus > 0) && (!is_multi_instance_service_for_dpu(instance_name)))) {
replace_multi_inst_dep(file_path);
}
free(instance_name);
@ -366,7 +505,14 @@ int get_unit_files(char* unit_files[]) {
if ((strcmp(line, "topology.service") == 0) &&
(num_asics == 1)) {
continue;
} else if ((strcmp(line, "midplane-network-dpu.service") == 0) &&
!smart_switch_dpu) {
continue;
} else if ((strcmp(line, "midplane-network-npu.service") == 0) &&
!smart_switch_npu) {
continue;
}
unit_files[num_unit_files] = strdup(line);
num_unit_files++;
}
@ -379,7 +525,7 @@ int get_unit_files(char* unit_files[]) {
}
char* insert_instance_number(char* unit_file, int instance) {
char* insert_instance_number(char* unit_file, int instance, const char *instance_prefix) {
/***
Adds an instance number to a systemd template name
@ -395,12 +541,16 @@ char* insert_instance_number(char* unit_file, int instance) {
return NULL;
}
if (instance_prefix == NULL) {
instance_prefix = "";
}
/***
suffix is "@.service", set suffix=".service"
prefix_len is length of "example@"
***/
prefix_len = ++suffix - unit_file;
ret = asprintf(&instance_name, "%.*s%d%s", prefix_len, unit_file, instance, suffix);
ret = asprintf(&instance_name, "%.*s%s%d%s", prefix_len, unit_file, instance_prefix, instance, suffix);
if (ret == -1) {
fprintf(stderr, "Error creating instance %d of %s\n", instance, unit_file);
return NULL;
@ -410,7 +560,7 @@ char* insert_instance_number(char* unit_file, int instance) {
}
static int create_symlink(char* unit, char* target, char* install_dir, int instance) {
static int create_symlink(char* unit, char* target, char* install_dir, int instance, const char *instance_prefix) {
struct stat st;
char src_path[PATH_MAX];
char dest_path[PATH_MAX];
@ -425,7 +575,7 @@ static int create_symlink(char* unit, char* target, char* install_dir, int insta
unit_instance = strdup(unit);
}
else {
unit_instance = insert_instance_number(unit, instance);
unit_instance = insert_instance_number(unit, instance, instance_prefix);
}
strcpy(final_install_dir, install_dir);
@ -467,6 +617,13 @@ static int create_symlink(char* unit, char* target, char* install_dir, int insta
}
}
if (is_devnull(dest_path)) {
if (remove(dest_path) != 0) {
fprintf(stderr, "Unable to remove existing symlink %s\n", dest_path);
return -1;
}
}
r = symlink(src_path, dest_path);
if (r < 0) {
@ -506,22 +663,31 @@ static int install_unit_file(char* unit_file, char* target, char* install_dir) {
for (int i = 0; i < num_asics; i++) {
if (strstr(target, "@") != NULL) {
target_instance = insert_instance_number(target, i);
target_instance = insert_instance_number(target, i, "");
}
else {
target_instance = strdup(target);
}
r = create_symlink(unit_file, target_instance, install_dir, i);
r = create_symlink(unit_file, target_instance, install_dir, i, "");
if (r < 0)
fprintf(stderr, "Error installing %s for target %s\n", unit_file, target_instance);
free(target_instance);
}
}
else {
r = create_symlink(unit_file, target, install_dir, -1);
} else if (num_dpus > 0 && strstr(unit_file, "@") != NULL) {
// If multi-instance service for DPU
// Install each DPU units to the host main instance only,
// E.g. install database@dpu0.service, database@dpu1.service to multi-user.target.wants
// We don't have case like to install xxx@dpu0.service to swss@dpu0.service.wants
for (int i = 0; i < num_dpus; i++) {
r = create_symlink(unit_file, target, install_dir, i, DPU_PREFIX);
if (r < 0)
fprintf(stderr, "Error installing %s for target %s\n", unit_file, target);
}
} else {
r = create_symlink(unit_file, target, install_dir, -1, "");
if (r < 0)
fprintf(stderr, "Error installing %s for target %s\n", unit_file, target);
}
@ -530,6 +696,61 @@ static int install_unit_file(char* unit_file, char* target, char* install_dir) {
}
/**
* Retrieves the platform name from the machine configuration file.
* If the platform name is already cached, it returns the cached value.
* If the platform name is not found in the configuration file, it sets the platform pointer to NULL.
*
* @return The platform name if found, otherwise NULL.
*/
const char* get_platform() {
if (is_initialized_pointer(platform)) {
if (is_valid_pointer(platform)) {
return platform;
} else {
return NULL;
}
}
FILE* fp;
char* line = NULL;
char* token;
char* saveptr;
char *tmp_platform = NULL;
static char platform_buffer[MAX_PLATFORM_NAME_LEN + 1];
size_t len = 0;
ssize_t nread;
const char* machine_config_file = get_machine_config_file();
fp = fopen(machine_config_file, "r");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s\n", machine_config_file);
exit(EXIT_FAILURE);
}
while ((nread = getline(&line, &len, fp)) != -1) {
if ((strstr(line, "onie_platform") != NULL) ||
(strstr(line, "aboot_platform") != NULL)) {
token = strtok_r(line, "=", &saveptr);
tmp_platform = strtok_r(NULL, "=", &saveptr);
strip_trailing_newline(tmp_platform);
break;
}
}
if (tmp_platform == NULL) {
set_invalid_pointer((void **)&platform);
fclose(fp);
free(line);
return NULL;
}
strncpy(platform_buffer, tmp_platform, sizeof(platform_buffer) - 1);
fclose(fp);
free(line);
platform = platform_buffer;
return platform;
}
int get_num_of_asic() {
/***
Determines if the current platform is single or multi-ASIC
@ -537,33 +758,16 @@ int get_num_of_asic() {
FILE *fp;
char *line = NULL;
char* token;
char* platform = NULL;
const char* platform = NULL;
char* saveptr;
size_t len = 0;
ssize_t nread;
bool ans;
char asic_file[512];
char* str_num_asic;
int num_asic = 1;
const char* machine_config_file = get_machine_config_file();
fp = fopen(machine_config_file, "r");
platform = get_platform();
if (fp == NULL) {
fprintf(stderr, "Failed to open %s\n", machine_config_file);
exit(EXIT_FAILURE);
}
while ((nread = getline(&line, &len, fp)) != -1) {
if ((strstr(line, "onie_platform") != NULL) ||
(strstr(line, "aboot_platform") != NULL)) {
token = strtok_r(line, "=", &saveptr);
platform = strtok_r(NULL, "=", &saveptr);
strip_trailing_newline(platform);
break;
}
}
fclose(fp);
if(platform != NULL) {
snprintf(asic_file, 512, get_asic_conf_format(), platform);
fp = fopen(asic_file, "r");
@ -587,6 +791,331 @@ int get_num_of_asic() {
}
/**
* Retrieves the platform information.
*
* This function reads the platform information from a JSON file and returns it as a JSON object.
* If the platform information has already been retrieved, it returns the cached value.
*
* @return The platform information as a JSON object, or NULL if it fails to retrieve or parse the information.
*/
const struct json_object* get_platform_info() {
if (is_initialized_pointer(platform_info)) {
if (is_valid_pointer(platform_info)) {
return platform_info;
} else {
return NULL;
}
}
char platform_file_path[PATH_MAX];
const char* platform = get_platform();
if (platform == NULL) {
set_invalid_pointer((void **)&platform_info);
return NULL;
}
snprintf(platform_file_path, sizeof(platform_file_path), get_platform_file_format(), platform);
FILE *fp = fopen(platform_file_path, "r");
if (fp == NULL) {
fprintf(stdout, "Failed to open %s\n", platform_file_path);
set_invalid_pointer((void **)&platform_info);
return NULL;
}
if (fseek(fp, 0, SEEK_END) != 0) {
fprintf(stdout, "Failed to seek to end of %s\n", platform_file_path);
fclose(fp);
exit(EXIT_FAILURE);
}
size_t fsize = ftell(fp);
if (fseek(fp, 0, SEEK_SET) != 0) {
fprintf(stdout, "Failed to seek to beginning of %s\n", platform_file_path);
fclose(fp);
exit(EXIT_FAILURE);
}
char *platform_json = malloc(fsize + 1);
if (platform_json == NULL) {
fprintf(stdout, "Failed to allocate memory for %s\n", platform_file_path);
fclose(fp);
exit(EXIT_FAILURE);
}
if (fread(platform_json, fsize, 1, fp) != 1) {
fprintf(stdout, "Failed to read %s\n", platform_file_path);
free(platform_json);
fclose(fp);
exit(EXIT_FAILURE);
}
fclose(fp);
platform_json[fsize] = '\0';
platform_info = json_tokener_parse(platform_json);
if (platform_info == NULL) {
fprintf(stderr, "Failed to parse %s\n", platform_file_path);
free(platform_json);
return NULL;
}
free(platform_json);
return platform_info;
}
/**
* Checks if the platform is a smart switch with an NPU (Network Processing Unit).
*
* @return true if the platform is a smart switch with an NPU, false otherwise.
*/
static bool is_smart_switch_npu() {
struct json_object *dpus;
const struct json_object *platform_info = get_platform_info();
if (platform_info == NULL) {
return false;
}
return json_object_object_get_ex(platform_info, "DPUS", &dpus);
}
/**
* Checks if the current platform is a smart switch with a DPU (Data Processing Unit).
*
* @return true if the platform is a smart switch with a DPU, false otherwise.
*/
static bool is_smart_switch_dpu() {
struct json_object *dpu;
const struct json_object *platform_info = get_platform_info();
if (platform_info == NULL) {
return false;
}
return json_object_object_get_ex(platform_info, "DPU", &dpu);
}
/**
* @brief Retrieves the number of DPUs (Data Processing Units).
*
* This function retrieves the number of DPUs by accessing the platform information
* and extracting the "DPUS" array from it. If the platform information is not available
* or the "DPUS" array does not exist, the function returns 0.
*
* @return The number of DPUs.
*/
static int get_num_of_dpu() {
struct json_object *dpus;
const struct json_object *platform_info = get_platform_info();
if (platform_info == NULL) {
return 0;
}
if (!json_object_object_get_ex(platform_info, "DPUS", &dpus)) {
return 0;
}
size_t num_dpu = 0;
json_object_object_foreach(dpus, key, val) {
num_dpu++;
}
return num_dpu;
}
/**
* Installs the network service.
*
* This function installs the network service by creating a symlink
* to the network service file in the appropriate directory.
*
* @param unit_name The name of the network unit to install.
* @return 0 if the network unit is installed successfully, or -1 if an error occurs.
*/
static int install_network_unit(const char* unit_name) {
assert(unit_name);
const char* unit_type = strrchr(unit_name, '.');
if (unit_type == NULL) {
fprintf(stderr, "Invalid network unit %s\n", unit_name);
return -1;
}
unit_type++;
char install_path[PATH_MAX] = {0};
char original_path[PATH_MAX] = {0};
const char* subdir;
if (strcmp(unit_type, "netdev") == 0 || strcmp(unit_type, "network") == 0) {
subdir = "/network/";
} else {
fprintf(stderr, "Invalid network unit %s\n", unit_type);
return -1;
}
strcpy(install_path, get_etc_systemd());
strcat(install_path, subdir);
strcat(install_path, unit_name);
strcpy(original_path, get_lib_systemd());
strcat(original_path, subdir);
strcat(original_path, unit_name);
struct stat st;
if (stat((const char *)install_path, &st) == 0) {
// If the file already exists, remove it
if (S_ISDIR(st.st_mode)) {
fprintf(stderr, "Error: %s is a directory\n", install_path);
return -1;
}
if (remove(install_path) != 0) {
fprintf(stderr, "Error removing existing file %s\n", install_path);
return -1;
}
}
if (is_devnull(install_path)) {
if (remove(install_path) != 0) {
fprintf(stderr, "Unable to remove existing symlink %s\n", install_path);
return -1;
}
}
if (symlink(original_path, install_path) != 0) {
if (errno == EEXIST)
return 0;
fprintf(stderr, "Error creating symlink %s -> %s (%s)\n", install_path, original_path, strerror(errno));
return -1;
}
return 0;
}
static int render_network_service_for_smart_switch() {
if (!smart_switch_npu) {
return 0;
}
// Render Before instruction for midplane network with database service
if (num_dpus == 0) {
return 0;
}
char buffer_instruction[MAX_BUF_SIZE] = {0};
strcpy(buffer_instruction, "\nBefore=");
for (size_t i = 0; i < num_dpus; i++) {
char *unit;
asprintf(&unit, "database@dpu%ld.service", i);
strcat(buffer_instruction, unit);
free(unit);
if (i != num_dpus - 1) {
strcat(buffer_instruction, " ");
}
}
char unit_path[PATH_MAX] = { 0 };
strcpy(unit_path, get_unit_file_prefix());
strcat(unit_path, "/midplane-network-npu.service");
FILE *fp = fopen(unit_path, "r");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s\n", unit_path);
return -1;
}
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
size_t len = file_size + strlen(buffer_instruction) + 1;
char *unit_content = malloc(len);
if (unit_content == NULL) {
fprintf(stderr, "Failed to allocate memory for %s\n", unit_path);
fclose(fp);
exit(EXIT_FAILURE);
}
if (fread(unit_content, file_size, 1, fp) != 1) {
fprintf(stderr, "Failed to read %s\n", unit_path);
free(unit_content);
fclose(fp);
exit(EXIT_FAILURE);
}
fclose(fp);
// Find insert point for Before instruction
char *insert_point = strstr(unit_content, "[Unit]");
insert_point += strlen("[Unit]");
// Move the rest of the file to make room for the Before instruction
memmove(insert_point + strlen(buffer_instruction), insert_point, file_size - (insert_point - unit_content));
// Insert the Before instruction
memcpy(insert_point, buffer_instruction, strlen(buffer_instruction));
// Remove original Before instruction
insert_point += strlen(buffer_instruction);
char *before_start = strstr(insert_point, "Before=");
while (before_start != NULL) {
char *before_end = strchr(before_start, '\n');
if (before_end == NULL) {
before_end = before_start + strlen(before_start);
} else {
// Include newline character
before_end += 1;
}
const char *target_service = strstr(before_start, "database@dpu");
if (target_service != NULL && target_service < before_end) {
memmove(before_start, before_end, strlen(before_end) + 1);
} else {
before_start = before_end;
}
before_start = strstr(before_start, "Before=");
}
// Write the modified unit file
fp = fopen(unit_path, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s\n", unit_path);
free(unit_content);
exit(EXIT_FAILURE);
}
if (fwrite(unit_content, strlen(unit_content), 1, fp) != 1) {
fprintf(stderr, "Failed to write %s\n", unit_path);
free(unit_content);
fclose(fp);
exit(EXIT_FAILURE);
}
fclose(fp);
free(unit_content);
return 0;
}
static int install_network_service_for_smart_switch() {
const char** network_units = NULL;
if (smart_switch_npu) {
static const char* npu_network_units[] = {
"bridge-midplane.netdev",
"bridge-midplane.network",
"dummy-midplane.netdev",
"dummy-midplane.network",
"midplane-network-npu.network",
NULL
};
network_units = npu_network_units;
} else if (smart_switch_dpu) {
static const char* dpu_network_units[] = {
"midplane-network-dpu.network",
NULL
};
network_units = dpu_network_units;
} else {
return -1;
}
if (network_units == NULL) {
return 0;
}
while(*network_units) {
if (install_network_unit(*network_units) != 0) {
return -1;
}
network_units++;
}
return 0;
}
int ssg_main(int argc, char **argv) {
char* unit_files[MAX_NUM_UNITS];
char install_dir[PATH_MAX];
@ -599,20 +1128,41 @@ int ssg_main(int argc, char **argv) {
int num_targets;
int r;
#ifdef _SSG_UNITTEST
clean_up_cache();
#endif
if (argc <= 1) {
fputs("Installation directory required as argument\n", stderr);
return 1;
}
num_asics = get_num_of_asic();
smart_switch_npu = is_smart_switch_npu();
smart_switch_dpu = is_smart_switch_dpu();
smart_switch = smart_switch_npu || smart_switch_dpu;
num_dpus = get_num_of_dpu();
strcpy(install_dir, argv[1]);
strcat(install_dir, "/");
num_unit_files = get_unit_files(unit_files);
// Install and render midplane network service for smart switch
if (smart_switch) {
if (render_network_service_for_smart_switch() != 0) {
return -1;
}
if (install_network_service_for_smart_switch() != 0) {
return -1;
}
}
// For each unit file, get the installation targets and install the unit
for (int i = 0; i < num_unit_files; i++) {
unit_instance = strdup(unit_files[i]);
if ((num_asics == 1) && strstr(unit_instance, "@") != NULL) {
if ((num_asics == 1 &&
!is_multi_instance_service_for_dpu(unit_instance)) &&
strstr(unit_instance, "@") != NULL) {
prefix = strdup(strtok_r(unit_instance, "@", &saveptr));
suffix = strdup(strtok_r(NULL, "@", &saveptr));
@ -647,6 +1197,10 @@ int ssg_main(int argc, char **argv) {
}
free(multi_instance_services);
if (is_valid_pointer(platform_info)) {
json_object_put(platform_info);
}
return 0;
}

View File

@ -15,17 +15,21 @@ extern const char* UNIT_FILE_PREFIX;
extern const char* CONFIG_FILE;
extern const char* MACHINE_CONF_FILE;
extern const char* ASIC_CONF_FORMAT;
extern const char* g_unit_file_prefix;
extern const char* PLATFORM_FILE_FORMAT;
extern const char* g_lib_systemd;
extern const char* g_etc_systemd;
extern const char* g_unit_file_prefix;
extern const char* g_config_file;
extern const char* g_machine_config_file;
extern const char* g_asic_conf_format;
extern const char* g_platform_file_format;
/* C-functions under test */
extern const char* get_unit_file_prefix();
extern const char* get_config_file();
extern const char* get_machine_config_file();
extern const char* get_asic_conf_format();
extern char* insert_instance_number(char* unit_file, int instance);
extern char* insert_instance_number(char* unit_file, int instance, const char *instance_prefix);
extern int ssg_main(int argc, char** argv);
extern int get_num_of_asic();
extern int get_install_targets(char* unit_file, char* targets[]);

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/bridge-midplane.netdev

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/bridge-midplane.network

View File

@ -0,0 +1,14 @@
[Unit]
Description=Database container
StartLimitIntervalSec=1200
StartLimitBurst=3
[Service]
User=root
ExecStartPre=/usr/local/bin/database.sh start
ExecStart=/usr/local/bin/database.sh wait
ExecStop=/usr/local/bin/database.sh stop
RestartSec=30
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,14 @@
[Unit]
Description=Database container
StartLimitIntervalSec=1200
StartLimitBurst=3
[Service]
User=root
ExecStartPre=/usr/local/bin/database.sh start %i
ExecStart=/usr/local/bin/database.sh wait %i
ExecStop=/usr/local/bin/database.sh stop %i
RestartSec=30
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/dummy-midplane.netdev

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/dummy-midplane.network

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/midplane-network-dpu.network

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/midplane-network-dpu.service

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/midplane-network-npu.network

View File

@ -0,0 +1 @@
../../../../files/image_config/midplane-network/midplane-network-npu.service