Commit 39e31edd authored by aligungr's avatar aligungr

gNB CLI introduction

parent dab099f2
...@@ -6,19 +6,35 @@ ...@@ -6,19 +6,35 @@
// and subject to the terms and conditions defined in LICENSE file. // and subject to the terms and conditions defined in LICENSE file.
// //
#include <utils/common.hpp> #include <app/base_app.hpp>
#include <utils/constants.hpp> #include <app/cli_cmd.hpp>
#include <cxxopts/cxxopts.hpp> #include <app/node_cli.hpp>
#include <app/proc_table.hpp>
#include <gnb/gnb.hpp> #include <gnb/gnb.hpp>
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
#include <yaml-cpp/yaml.h> #include <unordered_map>
#include <utils/common.hpp>
#include <utils/constants.hpp>
#include <utils/io.hpp>
#include <utils/options.hpp>
#include <utils/yaml_utils.hpp> #include <utils/yaml_utils.hpp>
#include <yaml-cpp/yaml.h>
static nr::gnb::GnbConfig *ReadConfigYaml(const std::string &file) static app::CliServer *g_cliServer = nullptr;
static nr::gnb::GnbConfig *g_refConfig = nullptr;
static std::unordered_map<std::string, nr::gnb::GNodeB *> g_gnbMap{};
static struct Options
{
std::string configFile{};
bool disableCmd{};
} g_options{};
static nr::gnb::GnbConfig *ReadConfigYaml()
{ {
auto *result = new nr::gnb::GnbConfig(); auto *result = new nr::gnb::GnbConfig();
auto config = YAML::LoadFile(file); auto config = YAML::LoadFile(g_options.configFile);
result->plmn.mcc = yaml::GetInt32(config, "mcc", 1, 999); result->plmn.mcc = yaml::GetInt32(config, "mcc", 1, 999);
yaml::GetString(config, "mcc", 3, 3); yaml::GetString(config, "mcc", 3, 3);
...@@ -58,56 +74,123 @@ static nr::gnb::GnbConfig *ReadConfigYaml(const std::string &file) ...@@ -58,56 +74,123 @@ static nr::gnb::GnbConfig *ReadConfigYaml(const std::string &file)
return result; return result;
} }
static nr::gnb::GnbConfig *GetConfig(const std::string &file) static void ReadOptions(int argc, char **argv)
{ {
try opt::OptionsDescription desc{cons::Project, cons::Tag, "5G-SA gNB implementation",
cons::Owner, "nr-cli", {"-c <config-file> [option...]"},
true};
opt::OptionItem itemConfigFile = {'c', "config", "Use specified configuration file for gNB", "config-file"};
opt::OptionItem itemDisableCmd = {'l', "disable-cmd", "Disable command line functionality for this instance",
std::nullopt};
desc.items.push_back(itemConfigFile);
desc.items.push_back(itemDisableCmd);
opt::OptionsResult opt{argc, argv, desc, false, nullptr};
if (opt.hasFlag(itemDisableCmd))
g_options.disableCmd = true;
g_options.configFile = opt.getOption(itemConfigFile);
g_refConfig = ReadConfigYaml();
}
static void ReceiveCommand(app::CliMessage &msg)
{
if (msg.value.empty())
{ {
return ReadConfigYaml(file); g_cliServer->sendMessage(app::CliMessage::Result(msg.clientAddr, ""));
return;
} }
catch (const std::runtime_error &e)
std::vector<std::string> tokens{};
auto exp = opt::PerformExpansion(msg.value, tokens);
if (exp != opt::ExpansionResult::SUCCESS)
{ {
std::cerr << "ERROR: " << e.what() << std::endl; g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, "Invalid command: " + msg.value));
exit(1); return;
} }
if (tokens.empty())
{
g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, "Empty command"));
return;
}
std::string error{}, output{};
auto cmd = app::ParseGnbCliCommand(std::move(tokens), error, output);
if (!error.empty())
{
g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, error));
return;
}
if (!output.empty())
{
g_cliServer->sendMessage(app::CliMessage::Result(msg.clientAddr, output));
return;
}
if (cmd == nullptr)
{
g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, ""));
return;
}
// TODO
g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, "Not implemented yet"));
} }
static void ReadOptions(int argc, char **argv, std::string &configFile) static void Loop()
{ {
try if (!g_cliServer)
{ {
cxxopts::Options options("nr-gnb", "5G-SA gNB implementation | Copyright (c) 2021 Ali Güngör"); ::pause();
options.add_options()("c,config", "Use specified configuration file for gNB", return;
cxxopts::value<std::string>())("h,help", "Show this help message and exit"); }
auto result = options.parse(argc, argv); auto msg = g_cliServer->receiveMessage();
if (msg.type == app::CliMessage::Type::ECHO)
{
g_cliServer->sendMessage(msg);
return;
}
if (result.arguments().empty() || result.count("help")) if (msg.type != app::CliMessage::Type::COMMAND)
{ return;
std::cout << options.help() << std::endl;
exit(0);
}
configFile = result["config"].as<std::string>(); if (msg.value.size() > 0xFFFF)
{
g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, "Command is too large"));
return;
} }
catch (const cxxopts::OptionException &e)
if (msg.nodeName.size() > 0xFFFF)
{ {
std::cerr << "ERROR: " << e.what() << std::endl; g_cliServer->sendMessage(app::CliMessage::Error(msg.clientAddr, "Node name is too large"));
exit(1); return;
} }
ReceiveCommand(msg);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
std::cout << cons::Name << std::endl; app::Initialize();
ReadOptions(argc, argv);
std::string configFile;
ReadOptions(argc, argv, configFile);
nr::gnb::GnbConfig *config = GetConfig(configFile); std::cout << cons::Name << std::endl;
auto *gnb = new nr::gnb::GNodeB(config, nullptr); auto *gnb = new nr::gnb::GNodeB(g_refConfig, nullptr);
g_gnbMap[g_refConfig->name] = gnb;
gnb->start(); gnb->start();
if (!g_options.disableCmd)
{
g_cliServer = new app::CliServer{};
app::CreateProcTable(g_gnbMap, g_cliServer->assignedAddress().getPort());
}
while (true) while (true)
::pause(); Loop();
} }
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment