mirror of https://github.com/pvnis/srsRAN_4G.git
remove legacy PNF/VNF code
the code hasn't been maintained for a while an likely needs to be adapted for a real-world scenarios. in order to avoid having to maintain two MAC/PHY interfaces we remove the code from now.master
parent
5ed241fc9b
commit
6c82d63aa6
@ -1,549 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_BASIC_PNF_H
|
||||
#define SRSRAN_BASIC_PNF_H
|
||||
|
||||
#include "basic_vnf_api.h"
|
||||
#include "common.h"
|
||||
#include "srsran/adt/choice_type.h"
|
||||
#include "srsran/common/block_queue.h"
|
||||
#include "srsran/common/buffer_pool.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <atomic>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <random>
|
||||
#include <strings.h>
|
||||
#include <sys/socket.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
#define RAND_SEED (12384)
|
||||
#define RX_TIMEOUT_MS (500)
|
||||
|
||||
#define MIN_TB_LEN (100) // MAX_TB_LEN defined in api.h
|
||||
|
||||
#define PING_REQUEST_PDU 1
|
||||
|
||||
namespace srsran {
|
||||
|
||||
struct pnf_metrics_t {
|
||||
uint32_t avg_rtt_us;
|
||||
uint32_t num_timing_errors;
|
||||
uint32_t num_pdus;
|
||||
uint32_t tb_size;
|
||||
};
|
||||
|
||||
class srsran_basic_pnf
|
||||
{
|
||||
using msg_header_t = basic_vnf_api::msg_header_t;
|
||||
const static size_t buffer_size =
|
||||
srsran::static_max<sizeof(basic_vnf_api::dl_conf_msg_t), sizeof(basic_vnf_api::tx_request_msg_t)>::value;
|
||||
using msg_buffer_t = std::array<uint8_t, buffer_size>;
|
||||
|
||||
public:
|
||||
srsran_basic_pnf(const std::string& type_,
|
||||
const std::string& vnf_p5_addr,
|
||||
const uint16_t& vnf_p5_port,
|
||||
const uint32_t& sf_interval,
|
||||
const int32_t& num_sf_,
|
||||
const uint32_t& tb_len_) :
|
||||
running(false),
|
||||
type(type_),
|
||||
tti(100), ///< Random start TTI
|
||||
vnf_addr(vnf_p5_addr),
|
||||
vnf_port(vnf_p5_port),
|
||||
sf_interval_us(sf_interval),
|
||||
num_sf(num_sf_),
|
||||
tb_len(tb_len_),
|
||||
rand_gen(RAND_SEED),
|
||||
rand_dist(MIN_TB_LEN, MAX_TB_LEN)
|
||||
{
|
||||
logger.set_level(srslog::basic_levels::warning);
|
||||
logger.set_hex_dump_max_size(-1);
|
||||
}
|
||||
|
||||
~srsran_basic_pnf() { stop(); };
|
||||
|
||||
bool start()
|
||||
{
|
||||
// create socket
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
perror("socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
int enable = 1;
|
||||
#if defined(SO_REUSEADDR)
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
|
||||
perror("setsockopt(SO_REUSEADDR) failed");
|
||||
}
|
||||
#endif
|
||||
#if defined(SO_REUSEPORT)
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
|
||||
perror("setsockopt(SO_REUSEPORT) failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
bzero(&servaddr, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = inet_addr(vnf_addr.c_str());
|
||||
servaddr.sin_port = htons(vnf_port);
|
||||
|
||||
// start main thread
|
||||
running = true;
|
||||
|
||||
if (type == "gnb") {
|
||||
rx_thread = std::unique_ptr<std::thread>(new std::thread(&srsran_basic_pnf::dl_handler_thread, this));
|
||||
tx_thread = std::unique_ptr<std::thread>(new std::thread(&srsran_basic_pnf::ul_handler_thread, this));
|
||||
} else {
|
||||
tx_thread = std::unique_ptr<std::thread>(new std::thread(&srsran_basic_pnf::ue_dl_handler_thread, this));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
bool stop()
|
||||
{
|
||||
running = false;
|
||||
|
||||
if (rx_thread) {
|
||||
if (rx_thread->joinable()) {
|
||||
rx_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
if (tx_thread) {
|
||||
if (tx_thread->joinable()) {
|
||||
tx_thread->join();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
pnf_metrics_t get_metrics()
|
||||
{
|
||||
pnf_metrics_t tmp = metrics;
|
||||
metrics = {};
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void connect_out_rf_queue(srsran::block_queue<srsran::unique_byte_buffer_t>* rf_queue_)
|
||||
{
|
||||
rf_out_queue = rf_queue_;
|
||||
policy = bridge;
|
||||
}
|
||||
srsran::block_queue<srsran::unique_byte_buffer_t>* get_in_rf_queue()
|
||||
{
|
||||
policy = bridge;
|
||||
return &rf_in_queue;
|
||||
}
|
||||
|
||||
private:
|
||||
//! Waits for DL Config or Tx Request Msg from VNF and forwards to RF
|
||||
void dl_handler_thread()
|
||||
{
|
||||
pthread_setname_np(pthread_self(), rx_thread_name.c_str());
|
||||
|
||||
// set_rt_prio();
|
||||
|
||||
struct pollfd fd;
|
||||
fd.fd = sockfd;
|
||||
fd.events = POLLIN;
|
||||
|
||||
std::unique_ptr<msg_buffer_t> rx_buffer{new msg_buffer_t{}};
|
||||
|
||||
while (running) {
|
||||
// receive response
|
||||
int ret = poll(&fd, 1, RX_TIMEOUT_MS);
|
||||
switch (ret) {
|
||||
case -1:
|
||||
printf("Error occurred.\n");
|
||||
running = false;
|
||||
break;
|
||||
case 0:
|
||||
// Timeout
|
||||
printf("Error: Didn't receive response after %dms\n", RX_TIMEOUT_MS);
|
||||
break;
|
||||
default:
|
||||
int recv_ret = recv(sockfd, rx_buffer->data(), sizeof(*rx_buffer), 0);
|
||||
handle_msg(rx_buffer->data(), recv_ret);
|
||||
break;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto rtt =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - tti_start_time)
|
||||
.count();
|
||||
|
||||
// TODO: add averaging
|
||||
metrics.avg_rtt_us = rtt;
|
||||
}
|
||||
};
|
||||
|
||||
void ul_handler_thread()
|
||||
{
|
||||
pthread_setname_np(pthread_self(), tx_thread_name.c_str());
|
||||
|
||||
// set_rt_prio();
|
||||
|
||||
struct pollfd fd;
|
||||
fd.fd = sockfd;
|
||||
fd.events = POLLIN;
|
||||
|
||||
const uint32_t max_basic_api_pdu = sizeof(basic_vnf_api::dl_conf_msg_t) + 32; // larger than biggest message
|
||||
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> > rx_buffer =
|
||||
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> >(new std::array<uint8_t, max_basic_api_pdu>);
|
||||
|
||||
int32_t sf_counter = 0;
|
||||
while (running && (num_sf > 0 ? sf_counter < num_sf : true)) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
// Increase TTI
|
||||
tti = (tti + 1) % 10240;
|
||||
|
||||
// Take time before sending the SF indication
|
||||
tti_start_time = std::chrono::steady_clock::now();
|
||||
|
||||
// Send request
|
||||
send_sf_ind(tti);
|
||||
|
||||
if (policy == bridge) {
|
||||
// send_rx_data_ind(tti);
|
||||
} else {
|
||||
// provide UL data every 2nd TTI
|
||||
if (tti % 2 == 0) {
|
||||
send_rx_data_ind(tti);
|
||||
}
|
||||
}
|
||||
|
||||
sf_counter++;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(sf_interval_us));
|
||||
}
|
||||
|
||||
printf("Leaving Tx thread after %d subframes\n", sf_counter);
|
||||
};
|
||||
|
||||
void ue_dl_handler_thread()
|
||||
{
|
||||
pthread_setname_np(pthread_self(), tx_thread_name.c_str());
|
||||
|
||||
// set_rt_prio();
|
||||
|
||||
struct pollfd fd;
|
||||
fd.fd = sockfd;
|
||||
fd.events = POLLIN;
|
||||
|
||||
const uint32_t max_basic_api_pdu = sizeof(basic_vnf_api::dl_conf_msg_t) + 32; // larger than biggest message
|
||||
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> > rx_buffer =
|
||||
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> >(new std::array<uint8_t, max_basic_api_pdu>);
|
||||
|
||||
int32_t sf_counter = 0;
|
||||
while (running && (num_sf > 0 ? sf_counter < num_sf : true)) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
// Increase TTI
|
||||
tti = (tti + 1) % 10240;
|
||||
|
||||
// Take time before sending the SF indication
|
||||
tti_start_time = std::chrono::steady_clock::now();
|
||||
|
||||
// Send SF indication
|
||||
send_sf_ind(tti);
|
||||
|
||||
if (policy == bridge) {
|
||||
srsran::unique_byte_buffer_t tb;
|
||||
if (rf_in_queue.try_pop(&tb)) {
|
||||
send_dl_ind(tti, std::move(tb));
|
||||
}
|
||||
} else {
|
||||
// provide DL grant every even TTI, and UL grant every odd
|
||||
if (tti % 2 == 0) {
|
||||
send_dl_ind(tti);
|
||||
} else {
|
||||
send_ul_ind(tti);
|
||||
}
|
||||
}
|
||||
|
||||
sf_counter++;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(sf_interval_us));
|
||||
}
|
||||
|
||||
printf("Leaving Tx thread after %d subframes\n", sf_counter);
|
||||
};
|
||||
|
||||
void send_sf_ind(uint32_t tti_)
|
||||
{
|
||||
basic_vnf_api::sf_ind_msg_t sf_ind;
|
||||
bzero(&sf_ind, sizeof(sf_ind));
|
||||
sf_ind.header.type = basic_vnf_api::SF_IND;
|
||||
sf_ind.header.msg_len = sizeof(sf_ind) - sizeof(basic_vnf_api::msg_header_t);
|
||||
sf_ind.tti = tti_;
|
||||
sf_ind.t1 = 0;
|
||||
sf_ind.tb_len = tb_len > 0 ? tb_len : rand_dist(rand_gen);
|
||||
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, &sf_ind, sizeof(sf_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
|
||||
printf("sendto failed, ret=%d\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
int handle_msg(const uint8_t* buffer, const uint32_t len)
|
||||
{
|
||||
basic_vnf_api::msg_header_t* header = (basic_vnf_api::msg_header_t*)buffer;
|
||||
|
||||
logger.debug("Received %s (%d B) in TTI", basic_vnf_api::msg_type_text[header->type], len);
|
||||
|
||||
switch (header->type) {
|
||||
case basic_vnf_api::SF_IND:
|
||||
printf("Error: %s not handled by VNF\n", basic_vnf_api::msg_type_text[header->type]);
|
||||
break;
|
||||
case basic_vnf_api::DL_CONFIG:
|
||||
handle_dl_config((basic_vnf_api::dl_conf_msg_t*)header);
|
||||
break;
|
||||
case basic_vnf_api::TX_REQUEST:
|
||||
handle_tx_request((basic_vnf_api::tx_request_msg_t*)header);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown msg type.\n");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_dl_config(basic_vnf_api::dl_conf_msg_t* msg)
|
||||
{
|
||||
// printf("Received DL config for TTI=%d\n", msg->tti);
|
||||
|
||||
if (msg->tti != tti) {
|
||||
metrics.num_timing_errors++;
|
||||
// printf("Received DL config for TTI=%d but current TTI is %d\n", msg->tti, tti.load());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_tx_request(basic_vnf_api::tx_request_msg_t* msg)
|
||||
{
|
||||
if (msg->tti != tti) {
|
||||
metrics.num_timing_errors++;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
|
||||
metrics.tb_size += msg->pdus[i].length;
|
||||
}
|
||||
|
||||
metrics.num_pdus += msg->nof_pdus;
|
||||
|
||||
if (rf_out_queue != nullptr) {
|
||||
uint32_t len = sizeof(*msg) - sizeof(msg->pdus->data) + msg->pdus->length;
|
||||
|
||||
srsran::unique_byte_buffer_t tx = srsran::make_byte_buffer();
|
||||
if (tx == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(tx->msg, msg, len);
|
||||
rf_out_queue->push(std::move(tx));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void send_rx_data_ind(const uint32_t tti_)
|
||||
{
|
||||
// MAC PDU for UL-SCH with IPv6 router solicitation
|
||||
static uint8_t tv[] = {0x04, 0x38, 0x00, 0x80, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0xff, 0xfe,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x44, 0x4b, 0x0f, 0x2c, 0x33, 0x98, 0xf2,
|
||||
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x85, 0x00, 0x4b, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7f, 0x00, 0x00, 0x3f, 0x00};
|
||||
|
||||
basic_vnf_api::rx_data_ind_msg_t rx_ind = {};
|
||||
|
||||
rx_ind.header.type = basic_vnf_api::RX_DATA_IND;
|
||||
rx_ind.header.msg_len = sizeof(rx_ind) - sizeof(basic_vnf_api::msg_header_t);
|
||||
rx_ind.sfn = tti_;
|
||||
rx_ind.t1 = 0;
|
||||
|
||||
rx_ind.nof_pdus = 1;
|
||||
rx_ind.pdus[0].type = basic_vnf_api::PUSCH;
|
||||
rx_ind.pdus[0].length = tb_len > 0 ? tb_len : rand_dist(rand_gen);
|
||||
|
||||
if (rx_ind.pdus[0].length >= sizeof(tv)) {
|
||||
// copy TV
|
||||
memcpy(rx_ind.pdus[0].data, tv, sizeof(tv));
|
||||
// set remaining bytes to zero
|
||||
memset(rx_ind.pdus[0].data + sizeof(tv), 0xaa, rx_ind.pdus[0].length - sizeof(tv));
|
||||
} else {
|
||||
// just fill with dummy bytes
|
||||
memset(rx_ind.pdus[0].data, 0xab, rx_ind.pdus[0].length);
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, &rx_ind, sizeof(rx_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
|
||||
printf("sendto failed, ret=%d\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
void send_dl_ind(uint32_t tti_, srsran::unique_byte_buffer_t tb = {})
|
||||
{
|
||||
#if PING_REQUEST_PDU
|
||||
static uint8_t tv[] = {
|
||||
0x04, 0x5c, 0x00, 0x80, 0x00, 0x00, 0x45, 0x00, 0x00, 0x54, 0x15, 0x02, 0x40, 0x00, 0x40, 0x01, 0xa2, 0x52,
|
||||
0xc0, 0xa8, 0x01, 0x01, 0xc0, 0xa8, 0x01, 0x03, 0x08, 0x00, 0x26, 0x40, 0x5e, 0x8f, 0x00, 0xb3, 0x04, 0x55,
|
||||
0xc4, 0x5d, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13,
|
||||
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x4f, 0x7f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
#else
|
||||
// MAC PDU with a single LCID with padding only
|
||||
static uint8_t tv[] = {
|
||||
0x01,
|
||||
0x08,
|
||||
0x11,
|
||||
0x22,
|
||||
0x33,
|
||||
0x44,
|
||||
0x55,
|
||||
0x66,
|
||||
0x77,
|
||||
0x88,
|
||||
0x3f,
|
||||
};
|
||||
#endif // PING_REQUEST_PDU
|
||||
basic_vnf_api::dl_ind_msg_t dl_ind = {};
|
||||
|
||||
dl_ind.header.type = basic_vnf_api::DL_IND;
|
||||
dl_ind.header.msg_len = sizeof(dl_ind) - sizeof(basic_vnf_api::msg_header_t);
|
||||
dl_ind.tti = tti_;
|
||||
dl_ind.t1 = 0;
|
||||
|
||||
uint32_t tot_bytes = 0;
|
||||
uint32_t tb_size = tb_len > 0 ? tb_len : rand_dist(rand_gen);
|
||||
|
||||
if (tb != nullptr) {
|
||||
auto* header = (basic_vnf_api::msg_header_t*)tb->msg;
|
||||
|
||||
if (header->type == basic_vnf_api::TX_REQUEST) {
|
||||
auto* tx_req = (basic_vnf_api::tx_request_msg_t*)tb->msg;
|
||||
dl_ind.nof_pdus = tx_req->nof_pdus;
|
||||
// dl_ind.tti = tx_req->tti;
|
||||
for (uint32_t i = 0; i < dl_ind.nof_pdus; ++i) {
|
||||
dl_ind.pdus[i].length = tx_req->pdus[i].length;
|
||||
dl_ind.pdus[i].type = tx_req->pdus[i].type;
|
||||
memcpy(dl_ind.pdus[i].data, tx_req->pdus[i].data, dl_ind.pdus[i].length);
|
||||
tot_bytes += dl_ind.pdus[i].length;
|
||||
logger.info(
|
||||
dl_ind.pdus[i].data, dl_ind.pdus[i].length, "Sending to UE a PDU (%d bytes)", dl_ind.pdus[i].length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t N_bytes = sizeof(tv);
|
||||
|
||||
// Create default
|
||||
dl_ind.nof_pdus = 1;
|
||||
dl_ind.pdus[0].type = basic_vnf_api::PDSCH;
|
||||
dl_ind.pdus[0].length = tb_size;
|
||||
|
||||
if (dl_ind.pdus[0].length >= N_bytes) {
|
||||
// copy TV
|
||||
memcpy(dl_ind.pdus[0].data, tv, N_bytes);
|
||||
tot_bytes = N_bytes;
|
||||
}
|
||||
|
||||
logger.info(dl_ind.pdus[0].data, N_bytes, "Sending to UE a TB (%d bytes)", N_bytes);
|
||||
}
|
||||
|
||||
if (tot_bytes > 0 and tot_bytes < tb_size) {
|
||||
uint8_t* offset = &dl_ind.pdus[dl_ind.nof_pdus - 1].data[dl_ind.pdus[dl_ind.nof_pdus - 1].length];
|
||||
memset(offset, 0xaa, tb_size - tot_bytes);
|
||||
} else if (tot_bytes == 0) {
|
||||
// just fill with dummy bytes
|
||||
dl_ind.nof_pdus = 1;
|
||||
memset(dl_ind.pdus[0].data, 0xab, tb_size);
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, &dl_ind, sizeof(dl_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
|
||||
printf("sendto failed, ret=%d\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
void send_ul_ind(uint32_t tti_)
|
||||
{
|
||||
basic_vnf_api::ul_ind_msg_t ul_ind = {};
|
||||
|
||||
ul_ind.header.type = basic_vnf_api::UL_IND;
|
||||
ul_ind.header.msg_len = sizeof(ul_ind) - sizeof(basic_vnf_api::msg_header_t);
|
||||
ul_ind.tti = tti_;
|
||||
ul_ind.t1 = 0;
|
||||
|
||||
ul_ind.pdus.type = basic_vnf_api::PUSCH;
|
||||
ul_ind.pdus.length = tb_len > 0 ? tb_len : rand_dist(rand_gen);
|
||||
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, &ul_ind, sizeof(ul_ind), 0, (struct sockaddr*)&servaddr, sizeof(servaddr))) < 0) {
|
||||
printf("sendto failed, ret=%d\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<std::thread> tx_thread, rx_thread;
|
||||
std::string tx_thread_name = "TX_PNF", rx_thread_name = "RX_PNF";
|
||||
bool running = false;
|
||||
srslog::basic_logger& logger = srslog::fetch_basic_logger("PNF", false);
|
||||
|
||||
std::mutex mutex;
|
||||
std::atomic<std::uint32_t> tti;
|
||||
std::chrono::steady_clock::time_point tti_start_time;
|
||||
|
||||
std::string type;
|
||||
|
||||
std::string vnf_addr;
|
||||
uint16_t vnf_port = 3333;
|
||||
|
||||
uint32_t sf_interval_us = 1000;
|
||||
int32_t num_sf = -1;
|
||||
uint32_t tb_len = 100;
|
||||
|
||||
pnf_metrics_t metrics = {};
|
||||
|
||||
int sockfd = 0;
|
||||
struct sockaddr_in servaddr = {};
|
||||
|
||||
// For random number generation
|
||||
std::mt19937 rand_gen;
|
||||
std::uniform_int_distribution<uint16_t> rand_dist;
|
||||
|
||||
// two policies possible: dummy packets generated by the PNF class, or bridge between UE and gNB PNFs with TBs
|
||||
// entering/exiting each PNF via the rf_in_queue/rf_out_queue.
|
||||
srsran::block_queue<srsran::unique_byte_buffer_t>* rf_out_queue = nullptr;
|
||||
srsran::block_queue<srsran::unique_byte_buffer_t> rf_in_queue;
|
||||
enum data_policy_t { self_gen, bridge } policy = self_gen;
|
||||
};
|
||||
|
||||
} // namespace srsran
|
||||
|
||||
#endif // SRSRAN_BASIC_PNF_H
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_BASIC_VNF_H
|
||||
#define SRSRAN_BASIC_VNF_H
|
||||
|
||||
#include "basic_vnf_api.h"
|
||||
#include "common.h"
|
||||
#include "srsran/common/threads.h"
|
||||
#include "srsran/interfaces/gnb_interfaces.h"
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include "srsran/srslog/srslog.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <netinet/in.h>
|
||||
#include <random>
|
||||
#include <strings.h>
|
||||
#include <sys/socket.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace srsran {
|
||||
|
||||
class srsran_basic_vnf : public thread
|
||||
{
|
||||
public:
|
||||
srsran_basic_vnf(const vnf_args_t& args_, stack_interface_phy_nr* stack_);
|
||||
~srsran_basic_vnf();
|
||||
|
||||
bool stop();
|
||||
|
||||
int dl_config_request(const srsenb::phy_interface_stack_nr::dl_config_request_t& request);
|
||||
int tx_request(const srsenb::phy_interface_stack_nr::tx_request_t& request);
|
||||
int tx_request(const srsue::phy_interface_stack_nr::tx_request_t& request);
|
||||
|
||||
private:
|
||||
void run_thread();
|
||||
|
||||
// handlers
|
||||
int handle_msg(const uint8_t* buffer, const uint32_t len);
|
||||
int handle_sf_ind(basic_vnf_api::sf_ind_msg_t* msg);
|
||||
int handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg);
|
||||
int handle_ul_ind(basic_vnf_api::ul_ind_msg_t* msg);
|
||||
int handle_rx_data_ind(basic_vnf_api::rx_data_ind_msg_t* msg);
|
||||
|
||||
// senders
|
||||
int send_dl_config_request();
|
||||
|
||||
// helpers
|
||||
uint32_t calc_full_msg_len(const basic_vnf_api::tx_request_msg_t& msg);
|
||||
|
||||
srslog::basic_logger& logger = srslog::fetch_basic_logger("VNF", false);
|
||||
srsenb::stack_interface_phy_nr* m_gnb_stack = nullptr;
|
||||
srsue::stack_interface_phy_nr* m_ue_stack = nullptr;
|
||||
|
||||
std::unique_ptr<basic_vnf_api::tx_request_msg_t> m_tx_req_msg;
|
||||
|
||||
bool running = false;
|
||||
|
||||
vnf_args_t m_args = {};
|
||||
|
||||
int sockfd = 0;
|
||||
struct sockaddr_in servaddr = {}, client_addr = {};
|
||||
|
||||
uint32_t last_sf_indication_time = 0;
|
||||
};
|
||||
|
||||
} // namespace srsran
|
||||
|
||||
#endif // SRSRAN_BASIC_VNF_H
|
@ -1,159 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSRAN_BASIC_VNF_API_H
|
||||
#define SRSRAN_BASIC_VNF_API_H
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace basic_vnf_api {
|
||||
|
||||
// PNF (the PHY) VNF (the L2/L3)
|
||||
// | |
|
||||
// | |
|
||||
// | - |
|
||||
// | \ sf_ind_msg_t
|
||||
// | \ |
|
||||
// | \ |
|
||||
// | \ |
|
||||
// | \ |
|
||||
// | \ |
|
||||
// | \|
|
||||
// | |
|
||||
// | | DL_CONFIG.request
|
||||
// | /|
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / dl_conf_msg_t
|
||||
// | / |
|
||||
// |/ | TX.request
|
||||
// | /|
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// | / tx_request_msg_t
|
||||
// | / |
|
||||
// |/ |
|
||||
// | |
|
||||
|
||||
// Primitive API messages for basic testing basic VNF/PNF interaction
|
||||
enum msg_type_t {
|
||||
SF_IND, ///< To signal start of new subframe (later slot) for both UE and gNB
|
||||
DL_CONFIG, ///< To configure the DL for gNB
|
||||
TX_REQUEST, ///< For DL data for gNB
|
||||
RX_DATA_IND, ///< For UL Data for gNB
|
||||
DL_IND, ///< For the UE for DL data
|
||||
UL_IND, ///< For the UE for UL Data
|
||||
MSG_TYPE_NITEMS
|
||||
};
|
||||
static const char* msg_type_text[MSG_TYPE_NITEMS] =
|
||||
{"SF Indication", "DL_CONFIG.Request", "TX.Request", "RX_Data.indication", "DL_Indication", "UL_Indication"};
|
||||
enum pdu_type_t { MAC_PBCH, PHY_PBCH, PDCCH, PDSCH, PUSCH };
|
||||
|
||||
struct msg_header_t {
|
||||
msg_type_t type;
|
||||
uint32_t msg_len;
|
||||
};
|
||||
|
||||
struct sf_ind_msg_t {
|
||||
msg_header_t header;
|
||||
uint32_t t1; // Timestamp taken at PNF
|
||||
uint32_t tti; // TTI of requested subframe
|
||||
uint32_t tb_len; // Length of the TB
|
||||
};
|
||||
|
||||
#define MAX_TB_LEN (16 * 1024)
|
||||
#define MAX_PDU_SIZE (16 * 1024)
|
||||
#define MAX_NUM_PDUS (1)
|
||||
|
||||
struct phy_pbch_pdu_t {
|
||||
uint16_t phy_cell_id; // 0 - 1007
|
||||
uint8_t ss_block_index; // 0-63
|
||||
uint8_t ssb_sc_offset; // 0-15
|
||||
uint8_t dmrs_pos; // 0-1
|
||||
uint8_t pdcch_config; // 0-255
|
||||
};
|
||||
|
||||
struct dl_conf_msg_t {
|
||||
msg_header_t header;
|
||||
uint32_t t1; // Replayed timestamp
|
||||
uint32_t t2; // Timestamp taken at VNF
|
||||
uint32_t tti; // TTI
|
||||
uint16_t beam_id; // tx beam id for the slot
|
||||
};
|
||||
|
||||
struct tx_request_pdu_t {
|
||||
uint16_t length;
|
||||
uint16_t index; // index indicated in dl_config
|
||||
pdu_type_t type; // physical chan of pdu/tb
|
||||
uint8_t data[MAX_PDU_SIZE];
|
||||
};
|
||||
|
||||
struct tx_request_msg_t {
|
||||
msg_header_t header;
|
||||
uint32_t tti; // TTI
|
||||
uint32_t tb_len; // actual TB len
|
||||
uint32_t nof_pdus;
|
||||
tx_request_pdu_t pdus[MAX_NUM_PDUS];
|
||||
};
|
||||
|
||||
struct rx_data_ind_pdu_t {
|
||||
uint16_t length;
|
||||
pdu_type_t type; // physical chan of pdu/tb
|
||||
uint8_t data[MAX_PDU_SIZE];
|
||||
};
|
||||
|
||||
struct rx_data_ind_msg_t {
|
||||
msg_header_t header;
|
||||
uint32_t t1; // Timestamp taken at PNF
|
||||
uint32_t sfn; ///< SFN (0-1023)
|
||||
uint32_t slot; ///< Slot (0-319)
|
||||
uint32_t tb_len; ///< actual TB len
|
||||
uint32_t nof_pdus; //
|
||||
rx_data_ind_pdu_t pdus[MAX_NUM_PDUS];
|
||||
};
|
||||
|
||||
// UE specific messages
|
||||
struct dl_ind_pdu_t {
|
||||
pdu_type_t type; // physical chan of pdu/tb
|
||||
uint16_t length;
|
||||
uint8_t data[MAX_PDU_SIZE];
|
||||
};
|
||||
|
||||
struct dl_ind_msg_t {
|
||||
msg_header_t header;
|
||||
uint32_t t1; // Timestamp taken at PNF
|
||||
uint32_t tti; // tti or slot?
|
||||
uint32_t nof_pdus;
|
||||
dl_ind_pdu_t pdus[MAX_NUM_PDUS];
|
||||
};
|
||||
|
||||
///< Messages for UL (only one PDU)
|
||||
struct ul_ind_pdu_t {
|
||||
pdu_type_t type; // physical chan of pdu/tb
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
struct ul_ind_msg_t {
|
||||
msg_header_t header;
|
||||
uint32_t t1; // Timestamp taken at PNF
|
||||
uint32_t tti; // tti or slot?
|
||||
uint32_t rnti; ///< RNTI of this grant
|
||||
ul_ind_pdu_t pdus;
|
||||
};
|
||||
|
||||
} // namespace basic_vnf_api
|
||||
|
||||
#endif // SRSRAN_BASIC_VNF_API_H
|
@ -1,399 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srsran/common/basic_vnf.h"
|
||||
#include "srsran/common/buffer_pool.h"
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <poll.h>
|
||||
|
||||
#define RAND_SEED (12314)
|
||||
#define RX_TIMEOUT_MS (1000)
|
||||
|
||||
namespace srsran {
|
||||
|
||||
struct srsran_pnf_info_t {
|
||||
// TODO: fill when needed
|
||||
};
|
||||
|
||||
struct srsran_vnf_info_t {};
|
||||
|
||||
srsran_basic_vnf::srsran_basic_vnf(const vnf_args_t& args_, stack_interface_phy_nr* stack_) :
|
||||
m_args(args_), thread("BASIC_VNF_P7"), m_tx_req_msg(new basic_vnf_api::tx_request_msg_t)
|
||||
{
|
||||
logger.set_level(srslog::str_to_basic_level(m_args.log_level));
|
||||
logger.set_hex_dump_max_size(m_args.log_hex_limit);
|
||||
|
||||
if (m_args.type == "gnb" || m_args.type == "ue") {
|
||||
if (m_args.type == "gnb") {
|
||||
m_gnb_stack = (srsenb::stack_interface_phy_nr*)stack_;
|
||||
} else {
|
||||
m_ue_stack = (srsue::stack_interface_phy_nr*)stack_;
|
||||
}
|
||||
|
||||
logger.info("Initializing VNF for gNB");
|
||||
start();
|
||||
} else {
|
||||
logger.error("Unknown VNF type. Exiting.");
|
||||
}
|
||||
}
|
||||
|
||||
srsran_basic_vnf::~srsran_basic_vnf()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void srsran_basic_vnf::run_thread()
|
||||
{
|
||||
// Bind to UDP socket
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
perror("socket");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sockets reusable
|
||||
int enable = 1;
|
||||
#if defined(SO_REUSEADDR)
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
|
||||
perror("setsockopt(SO_REUSEADDR) failed");
|
||||
}
|
||||
#endif
|
||||
#if defined(SO_REUSEPORT)
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) {
|
||||
perror("setsockopt(SO_REUSEPORT) failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
servaddr.sin_port = htons(m_args.bind_port);
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))) {
|
||||
perror("bind");
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd fd;
|
||||
fd.fd = sockfd;
|
||||
fd.events = POLLIN;
|
||||
|
||||
const uint32_t max_basic_api_pdu = sizeof(basic_vnf_api::dl_ind_msg_t) + 32; // larger than biggest message
|
||||
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> > rx_buffer =
|
||||
std::unique_ptr<std::array<uint8_t, max_basic_api_pdu> >(new std::array<uint8_t, max_basic_api_pdu>);
|
||||
|
||||
running = true;
|
||||
|
||||
logger.info("Started VNF handler listening on %s:%d", m_args.bind_addr.c_str(), m_args.bind_port);
|
||||
|
||||
while (running) {
|
||||
int ret = poll(&fd, 1, RX_TIMEOUT_MS);
|
||||
switch (ret) {
|
||||
case -1:
|
||||
printf("Error occured.\n");
|
||||
break;
|
||||
case 0:
|
||||
// Timeout
|
||||
break;
|
||||
default:
|
||||
|
||||
socklen_t len = sizeof(client_addr);
|
||||
ret = recvfrom(sockfd, rx_buffer->data(), rx_buffer->size(), MSG_WAITALL, (struct sockaddr*)&client_addr, &len);
|
||||
|
||||
handle_msg(rx_buffer->data(), ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
logger.info("VNF thread stopped");
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::handle_msg(const uint8_t* buffer, const uint32_t len)
|
||||
{
|
||||
basic_vnf_api::msg_header_t* header = (basic_vnf_api::msg_header_t*)buffer;
|
||||
|
||||
logger.info("Received %s (%d B)", basic_vnf_api::msg_type_text[header->type], len);
|
||||
|
||||
switch (header->type) {
|
||||
case basic_vnf_api::SF_IND:
|
||||
handle_sf_ind((basic_vnf_api::sf_ind_msg_t*)header);
|
||||
break;
|
||||
case basic_vnf_api::DL_CONFIG:
|
||||
printf("Error: %s not handled by VNF\n", basic_vnf_api::msg_type_text[header->type]);
|
||||
break;
|
||||
case basic_vnf_api::DL_IND:
|
||||
handle_dl_ind((basic_vnf_api::dl_ind_msg_t*)header);
|
||||
break;
|
||||
case basic_vnf_api::UL_IND:
|
||||
handle_ul_ind((basic_vnf_api::ul_ind_msg_t*)header);
|
||||
break;
|
||||
case basic_vnf_api::RX_DATA_IND:
|
||||
handle_rx_data_ind((basic_vnf_api::rx_data_ind_msg_t*)header);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown msg type.\n");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::handle_sf_ind(basic_vnf_api::sf_ind_msg_t* msg)
|
||||
{
|
||||
int ret = SRSRAN_SUCCESS;
|
||||
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->tti);
|
||||
|
||||
// store Rx timestamp
|
||||
last_sf_indication_time = msg->t1;
|
||||
|
||||
if (m_gnb_stack != nullptr) {
|
||||
srsran_slot_cfg_t slot_cfg = {};
|
||||
slot_cfg.idx = msg->tti;
|
||||
m_gnb_stack->slot_indication(slot_cfg);
|
||||
} else if (m_ue_stack != nullptr) {
|
||||
m_ue_stack->sf_indication(msg->tti);
|
||||
} else {
|
||||
ret = SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::handle_dl_ind(basic_vnf_api::dl_ind_msg_t* msg)
|
||||
{
|
||||
int ret = SRSRAN_ERROR;
|
||||
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->tti);
|
||||
|
||||
uint32_t cc_idx = 0;
|
||||
|
||||
// fill DL struct
|
||||
srsue::stack_interface_phy_nr::mac_nr_grant_dl_t dl_grant = {};
|
||||
dl_grant.tti = msg->tti;
|
||||
|
||||
if (msg->nof_pdus > SRSRAN_MAX_TB) {
|
||||
logger.error("Too many TBs (%d > %d)", msg->nof_pdus, SRSRAN_MAX_TB);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < msg->nof_pdus; ++i) {
|
||||
srsue::stack_interface_phy_nr::tb_action_dl_result_t result = {};
|
||||
result.payload = srsran::make_byte_buffer();
|
||||
if (result.payload != nullptr && result.payload->get_tailroom() >= msg->pdus[i].length) {
|
||||
result.ack = true;
|
||||
memcpy(result.payload->msg, msg->pdus[i].data, msg->pdus[i].length);
|
||||
result.payload->N_bytes = msg->pdus[i].length;
|
||||
if (msg->pdus[i].type == basic_vnf_api::PDSCH) {
|
||||
m_ue_stack->tb_decoded(cc_idx, dl_grant, std::move(result));
|
||||
}
|
||||
} else {
|
||||
logger.error("TB too big to fit into buffer (%d)", msg->pdus[i].length);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ret = SRSRAN_SUCCESS;
|
||||
|
||||
exit:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::handle_ul_ind(basic_vnf_api::ul_ind_msg_t* msg)
|
||||
{
|
||||
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->tti);
|
||||
|
||||
if (msg->pdus.type != basic_vnf_api::PUSCH) {
|
||||
logger.error("Received UL indication for wrong PDU type");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
uint32_t cc_idx = 0;
|
||||
|
||||
// fill DL struct
|
||||
srsue::stack_interface_phy_nr::mac_nr_grant_ul_t ul_grant = {};
|
||||
ul_grant.tti = msg->tti;
|
||||
ul_grant.tbs = msg->pdus.length;
|
||||
ul_grant.rnti = msg->rnti;
|
||||
|
||||
srsue::stack_interface_phy_nr::tb_action_ul_t ul_action = {};
|
||||
m_ue_stack->new_grant_ul(cc_idx, ul_grant, &ul_action);
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::handle_rx_data_ind(basic_vnf_api::rx_data_ind_msg_t* msg)
|
||||
{
|
||||
logger.info("Received %s for TTI=%d", basic_vnf_api::msg_type_text[msg->header.type], msg->sfn);
|
||||
|
||||
if (msg->nof_pdus != 1 || msg->pdus[0].type != basic_vnf_api::PUSCH) {
|
||||
logger.error("Received UL indication for wrong PDU type");
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
|
||||
// fill struct
|
||||
srsenb::stack_interface_phy_nr::rx_data_ind_t rx_data = {};
|
||||
rx_data.tti = msg->sfn;
|
||||
rx_data.tb = srsran::make_byte_buffer();
|
||||
if (rx_data.tb->get_tailroom() >= msg->pdus[0].length) {
|
||||
// copy actual data
|
||||
memcpy(rx_data.tb->msg, msg->pdus[0].data, msg->pdus[0].length);
|
||||
rx_data.tb->N_bytes = msg->pdus[0].length;
|
||||
if (msg->pdus[0].type == basic_vnf_api::PUSCH) {
|
||||
m_gnb_stack->rx_data_indication(rx_data);
|
||||
}
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::dl_config_request(const srsenb::phy_interface_stack_nr::dl_config_request_t& request)
|
||||
{
|
||||
// Generate DL Config
|
||||
basic_vnf_api::dl_conf_msg_t dl_conf = {};
|
||||
dl_conf.header.type = basic_vnf_api::DL_CONFIG;
|
||||
dl_conf.header.msg_len = sizeof(dl_conf) - sizeof(basic_vnf_api::msg_header_t);
|
||||
|
||||
dl_conf.t1 = last_sf_indication_time; // play back the time
|
||||
dl_conf.t2 = 0xaa; // TODO: add timestamp
|
||||
dl_conf.tti = request.tti;
|
||||
dl_conf.beam_id = request.beam_id;
|
||||
|
||||
// Send entire struct
|
||||
uint32_t len = sizeof(dl_conf);
|
||||
|
||||
// Send it to PNF
|
||||
logger.info("Sending %s (%d B)", basic_vnf_api::msg_type_text[dl_conf.header.type], len);
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, &dl_conf, len, MSG_CONFIRM, (struct sockaddr*)&client_addr, sizeof(client_addr))) < 0) {
|
||||
logger.error("sendto failed, ret=%d", n);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Tx request from UE, i.e. UL transmission
|
||||
int srsran_basic_vnf::tx_request(const srsue::phy_interface_stack_nr::tx_request_t& request)
|
||||
{
|
||||
// Generate Tx request
|
||||
m_tx_req_msg->header.type = basic_vnf_api::TX_REQUEST;
|
||||
m_tx_req_msg->header.msg_len = 0; // set further down
|
||||
|
||||
m_tx_req_msg->tti = request.tti;
|
||||
|
||||
m_tx_req_msg->nof_pdus = 1;
|
||||
m_tx_req_msg->pdus[0].index = 0;
|
||||
m_tx_req_msg->pdus[0].type = basic_vnf_api::PUSCH;
|
||||
m_tx_req_msg->pdus[0].length = request.tb_len;
|
||||
|
||||
if (request.tb_len <= MAX_PDU_SIZE) {
|
||||
// copy data from TB0
|
||||
memcpy(m_tx_req_msg->pdus[0].data, request.data, request.tb_len);
|
||||
} else {
|
||||
logger.error("Trying to send %d B PDU. Maximum size is %d B", request.tb_len, MAX_PDU_SIZE);
|
||||
}
|
||||
|
||||
// calculate actual length of
|
||||
uint32_t len = calc_full_msg_len(*m_tx_req_msg.get());
|
||||
|
||||
// update msg header length field
|
||||
m_tx_req_msg->header.msg_len = len - sizeof(basic_vnf_api::msg_header_t);
|
||||
|
||||
// Send it to PNF
|
||||
logger.info("Sending %s (%d B)", basic_vnf_api::msg_type_text[m_tx_req_msg->header.type], len);
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, m_tx_req_msg.get(), len, MSG_CONFIRM, (struct sockaddr*)&client_addr, sizeof(client_addr))) <
|
||||
0) {
|
||||
logger.error("sendto failed, ret=%d", n);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srsran_basic_vnf::tx_request(const srsenb::phy_interface_stack_nr::tx_request_t& request)
|
||||
{
|
||||
if (request.nof_pdus > MAX_NUM_PDUS) {
|
||||
logger.error("Trying to send %d PDUs but only %d supported", request.nof_pdus, MAX_NUM_PDUS);
|
||||
return SRSRAN_ERROR;
|
||||
}
|
||||
if (request.nof_pdus == 0) {
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// Generate Tx request
|
||||
m_tx_req_msg->header.type = basic_vnf_api::TX_REQUEST;
|
||||
m_tx_req_msg->header.msg_len = 0; // set further down
|
||||
|
||||
m_tx_req_msg->nof_pdus = request.nof_pdus;
|
||||
m_tx_req_msg->tti = request.tti;
|
||||
|
||||
for (uint32_t i = 0; i < m_tx_req_msg->nof_pdus; ++i) {
|
||||
if (request.pdus[i].length <= MAX_PDU_SIZE) {
|
||||
m_tx_req_msg->pdus[i].index = i;
|
||||
m_tx_req_msg->pdus[i].type = request.pdus[i].pbch.mib_present ? basic_vnf_api::MAC_PBCH : basic_vnf_api::PDSCH;
|
||||
m_tx_req_msg->pdus[i].length = request.pdus[i].length;
|
||||
// copy data from TB0
|
||||
memcpy(m_tx_req_msg->pdus[i].data, request.pdus[i].data[0], m_tx_req_msg->pdus[i].length);
|
||||
} else {
|
||||
logger.error("Trying to send %d B PDU. Maximum size is %d B", request.pdus[i].length, MAX_PDU_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate actual length of message
|
||||
uint32_t len = calc_full_msg_len(*m_tx_req_msg.get());
|
||||
|
||||
// update msg header length field
|
||||
m_tx_req_msg->header.msg_len = len - sizeof(basic_vnf_api::msg_header_t);
|
||||
|
||||
// Send it to PNF
|
||||
logger.info("Sending %s (%d B)", basic_vnf_api::msg_type_text[m_tx_req_msg->header.type], len);
|
||||
if (logger.debug.enabled()) {
|
||||
for (uint32_t i = 0; i < m_tx_req_msg->nof_pdus; ++i) {
|
||||
logger.debug(m_tx_req_msg->pdus[i].data,
|
||||
m_tx_req_msg->pdus[i].length,
|
||||
"Sending PDU %s:%d (%d bytes)",
|
||||
basic_vnf_api::msg_type_text[m_tx_req_msg->header.type],
|
||||
m_tx_req_msg->pdus[i].index,
|
||||
m_tx_req_msg->pdus[i].length);
|
||||
}
|
||||
}
|
||||
int n = 0;
|
||||
if ((n = sendto(sockfd, m_tx_req_msg.get(), len, MSG_CONFIRM, (struct sockaddr*)&client_addr, sizeof(client_addr))) <
|
||||
0) {
|
||||
logger.error("sendto failed, ret=%d", n);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t srsran_basic_vnf::calc_full_msg_len(const basic_vnf_api::tx_request_msg_t& msg)
|
||||
{
|
||||
// start with mandatory part
|
||||
uint32_t len = sizeof(basic_vnf_api::msg_header_t) + 3 * sizeof(uint32_t);
|
||||
|
||||
// add all PDUs
|
||||
for (uint32_t i = 0; i < msg.nof_pdus; ++i) {
|
||||
len += 2 * sizeof(uint16_t) + sizeof(basic_vnf_api::pdu_type_t) + msg.pdus[i].length;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool srsran_basic_vnf::stop()
|
||||
{
|
||||
if (running) {
|
||||
running = false;
|
||||
wait_thread_finish();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace srsran
|
@ -1,118 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <thread>
|
||||
|
||||
#include "srsran/common/basic_pnf.h"
|
||||
|
||||
using namespace std;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
struct pnf_args_t {
|
||||
std::string gnb_vnf_addr;
|
||||
std::string ue_vnf_addr;
|
||||
uint16_t gnb_vnf_port;
|
||||
uint16_t ue_vnf_port;
|
||||
uint32_t sf_interval;
|
||||
int32_t num_sf;
|
||||
uint32_t tb_len;
|
||||
};
|
||||
|
||||
void parse_args(pnf_args_t* args, int argc, char* argv[])
|
||||
{
|
||||
// Command line only options
|
||||
bpo::options_description general("General options");
|
||||
|
||||
general.add_options()("help,h", "Produce help message")("version,v", "Print version information and exit");
|
||||
|
||||
// Command line or config file options
|
||||
bpo::options_description common("Configuration options");
|
||||
|
||||
// clang-format off
|
||||
common.add_options()
|
||||
("vnf.gnb_addr", bpo::value<string>(&args->gnb_vnf_addr)->default_value("127.0.0.1"), "VNF address")
|
||||
("vnf.ue_addr", bpo::value<string>(&args->ue_vnf_addr)->default_value("127.0.0.1"), "VNF address")
|
||||
("vnf.gnb_port", bpo::value<uint16_t>(&args->gnb_vnf_port)->default_value(3333), "gNB VNF port")
|
||||
("vnf.ue_port", bpo::value<uint16_t>(&args->ue_vnf_port)->default_value(3334), "UE VNF port")
|
||||
("sf_interval", bpo::value<uint32_t>(&args->sf_interval)->default_value(1000), "Interval between subframes in us")
|
||||
("num_sf", bpo::value<int32_t>(&args->num_sf)->default_value(-1), "Number of subframes to signal (-1 infinity)")
|
||||
("tb_len", bpo::value<uint32_t>(&args->tb_len)->default_value(1600), "TB lenth (0 for random size)");
|
||||
// clang-format on
|
||||
|
||||
// these options are allowed on the command line
|
||||
bpo::options_description cmdline_options;
|
||||
cmdline_options.add(common).add(general);
|
||||
|
||||
// parse the command line and store result in vm
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
|
||||
bpo::notify(vm);
|
||||
|
||||
// help option was given - print usage and exit
|
||||
if (vm.count("help")) {
|
||||
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
|
||||
cout << common << endl << general << endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
void sig_int_handler(int signo)
|
||||
{
|
||||
printf("SIGINT received. Exiting...\n");
|
||||
if (signo == SIGINT) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
signal(SIGINT, sig_int_handler);
|
||||
|
||||
pnf_args_t args;
|
||||
parse_args(&args, argc, argv);
|
||||
|
||||
srsran::srsran_basic_pnf ue_pnf("ue", args.ue_vnf_addr, args.ue_vnf_port, args.sf_interval, args.num_sf, args.tb_len);
|
||||
srsran::srsran_basic_pnf gnb_pnf(
|
||||
"gnb", args.gnb_vnf_addr, args.gnb_vnf_port, args.sf_interval, args.num_sf, args.tb_len);
|
||||
|
||||
gnb_pnf.connect_out_rf_queue(ue_pnf.get_in_rf_queue());
|
||||
|
||||
ue_pnf.start();
|
||||
gnb_pnf.start();
|
||||
|
||||
while (running) {
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
srsran::pnf_metrics_t metrics = (i == 0) ? ue_pnf.get_metrics() : gnb_pnf.get_metrics();
|
||||
printf("%s: RTT=%d, #Error=%d, #PDUs=%d, Total TB size=%d, Rate=%.2f Mbit/s\n",
|
||||
i == 0 ? "UE" : "gNB",
|
||||
metrics.avg_rtt_us,
|
||||
metrics.num_timing_errors,
|
||||
metrics.num_pdus,
|
||||
metrics.tb_size,
|
||||
metrics.tb_size * 8 / 1.0e6);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
ue_pnf.stop();
|
||||
gnb_pnf.stop();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
#include <thread>
|
||||
|
||||
#include "srsran/common/basic_pnf.h"
|
||||
|
||||
using namespace std;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
struct pnf_args_t {
|
||||
std::string type;
|
||||
std::string vnf_addr;
|
||||
uint16_t vnf_port;
|
||||
uint32_t sf_interval;
|
||||
int32_t num_sf;
|
||||
uint32_t tb_len;
|
||||
};
|
||||
|
||||
void parse_args(pnf_args_t* args, int argc, char* argv[])
|
||||
{
|
||||
// Command line only options
|
||||
bpo::options_description general("General options");
|
||||
|
||||
general.add_options()("help,h", "Produce help message")("version,v", "Print version information and exit");
|
||||
|
||||
// Command line or config file options
|
||||
bpo::options_description common("Configuration options");
|
||||
|
||||
// clang-format off
|
||||
common.add_options()
|
||||
("vnf.type", bpo::value<string>(&args->type)->default_value("gnb"), "VNF instance type [gnb,ue]")
|
||||
("vnf.addr", bpo::value<string>(&args->vnf_addr)->default_value("127.0.0.1"), "VNF address")
|
||||
("vnf.port", bpo::value<uint16_t>(&args->vnf_port)->default_value(3333), "VNF port")
|
||||
("sf_interval", bpo::value<uint32_t>(&args->sf_interval)->default_value(1000), "Interval between subframes in us")
|
||||
("num_sf", bpo::value<int32_t>(&args->num_sf)->default_value(-1), "Number of subframes to signal (-1 infinity)")
|
||||
("tb_len", bpo::value<uint32_t>(&args->tb_len)->default_value(0), "TB lenth (0 for random size)");
|
||||
|
||||
// clang-format on
|
||||
|
||||
// these options are allowed on the command line
|
||||
bpo::options_description cmdline_options;
|
||||
cmdline_options.add(common).add(general);
|
||||
|
||||
// parse the command line and store result in vm
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
|
||||
bpo::notify(vm);
|
||||
|
||||
// help option was given - print usage and exit
|
||||
if (vm.count("help")) {
|
||||
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
|
||||
cout << common << endl << general << endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
void sig_int_handler(int signo)
|
||||
{
|
||||
printf("SIGINT received. Exiting...\n");
|
||||
if (signo == SIGINT) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
signal(SIGINT, sig_int_handler);
|
||||
|
||||
pnf_args_t args;
|
||||
parse_args(&args, argc, argv);
|
||||
|
||||
srsran::srsran_basic_pnf pnf(args.type, args.vnf_addr, args.vnf_port, args.sf_interval, args.num_sf, args.tb_len);
|
||||
|
||||
pnf.start();
|
||||
|
||||
while (running) {
|
||||
srsran::pnf_metrics_t metrics = pnf.get_metrics();
|
||||
printf("RTT=%d, #Error=%d, #PDUs=%d, Total TB size=%d, Rate=%.2f Mbit/s\n",
|
||||
metrics.avg_rtt_us,
|
||||
metrics.num_timing_errors,
|
||||
metrics.num_pdus,
|
||||
metrics.tb_size,
|
||||
metrics.tb_size * 8 / 1e6);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
pnf.stop();
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSGNB_NR_VNF_PHY_H
|
||||
#define SRSGNB_NR_VNF_PHY_H
|
||||
|
||||
#include "srsenb/hdr/phy/enb_phy_base.h"
|
||||
#include "srsenb/hdr/phy/phy_common.h"
|
||||
#include "srsran/common/basic_vnf.h"
|
||||
#include "srsran/interfaces/enb_metrics_interface.h"
|
||||
#include "srsran/interfaces/gnb_interfaces.h"
|
||||
#include "srsran/interfaces/radio_interfaces.h"
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
struct nr_phy_cfg_t {
|
||||
// TODO: add cell and RRC configs
|
||||
};
|
||||
|
||||
class vnf_phy_nr : public srsenb::enb_phy_base, public srsenb::phy_interface_stack_nr
|
||||
{
|
||||
public:
|
||||
vnf_phy_nr() = default;
|
||||
~vnf_phy_nr();
|
||||
|
||||
int init(const srsenb::phy_args_t& args, const nr_phy_cfg_t& cfg, srsenb::stack_interface_phy_nr* stack_);
|
||||
void stop() override;
|
||||
|
||||
std::string get_type() override { return "vnf"; };
|
||||
|
||||
void start_plot() override;
|
||||
|
||||
void get_metrics(std::vector<srsenb::phy_metrics_t>& metrics) override;
|
||||
|
||||
// MAC interface
|
||||
int dl_config_request(const dl_config_request_t& request) override;
|
||||
int tx_request(const tx_request_t& request) override;
|
||||
|
||||
void cmd_cell_gain(uint32_t cell_idx, float gain_db) override
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<srsran::srsran_basic_vnf> vnf = nullptr;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
void parse_config(const nr_phy_cfg_t& cfg);
|
||||
};
|
||||
|
||||
} // namespace srsenb
|
||||
|
||||
#endif // SRSGNB_NR_VNF_PHY_H
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "srsenb/hdr/phy/vnf_phy_nr.h"
|
||||
#include "srsran/common/basic_vnf_api.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace srsenb {
|
||||
|
||||
vnf_phy_nr::~vnf_phy_nr()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void vnf_phy_nr::parse_config(const nr_phy_cfg_t& cfg) {}
|
||||
|
||||
int vnf_phy_nr::init(const srsenb::phy_args_t& args, const nr_phy_cfg_t& cfg, srsenb::stack_interface_phy_nr* stack_)
|
||||
{
|
||||
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
|
||||
// create VNF
|
||||
vnf = std::unique_ptr<srsran::srsran_basic_vnf>(new srsran::srsran_basic_vnf(args.vnf_args, stack_));
|
||||
|
||||
initialized = true;
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
void vnf_phy_nr::stop()
|
||||
{
|
||||
if (initialized) {
|
||||
vnf->stop();
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Start GUI
|
||||
void vnf_phy_nr::start_plot() {}
|
||||
|
||||
void vnf_phy_nr::get_metrics(std::vector<srsenb::phy_metrics_t>& metrics) {}
|
||||
|
||||
int vnf_phy_nr::dl_config_request(const dl_config_request_t& request)
|
||||
{
|
||||
// prepare DL config request over basic API and send
|
||||
return vnf->dl_config_request(request);
|
||||
}
|
||||
|
||||
int vnf_phy_nr::tx_request(const tx_request_t& request)
|
||||
{
|
||||
// send Tx request over basic API
|
||||
return vnf->tx_request(request);
|
||||
}
|
||||
|
||||
} // namespace srsenb
|
@ -1,73 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_VNF_PHY_NR_H
|
||||
#define SRSUE_VNF_PHY_NR_H
|
||||
|
||||
#include "srsenb/hdr/phy/phy_common.h"
|
||||
#include "srsran/common/basic_vnf.h"
|
||||
#include "srsran/interfaces/enb_metrics_interface.h"
|
||||
#include "srsran/interfaces/radio_interfaces.h"
|
||||
#include "srsran/interfaces/ue_interfaces.h"
|
||||
#include "srsran/interfaces/ue_nr_interfaces.h"
|
||||
#include "srsue/hdr/phy/ue_nr_phy_base.h"
|
||||
|
||||
namespace srsue {
|
||||
|
||||
class vnf_phy_nr : public srsue::ue_phy_base, public srsue::phy_interface_stack_nr
|
||||
{
|
||||
public:
|
||||
vnf_phy_nr() = default;
|
||||
~vnf_phy_nr();
|
||||
|
||||
int init(const srsue::phy_args_t& args, srsue::stack_interface_phy_nr* stack_);
|
||||
|
||||
int init(const srsue::phy_args_t& args_) override;
|
||||
|
||||
void set_earfcn(std::vector<uint32_t> earfcns);
|
||||
|
||||
void stop() override;
|
||||
|
||||
void wait_initialize() override;
|
||||
void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) override;
|
||||
|
||||
std::string get_type() override { return "vnf_nr"; };
|
||||
|
||||
void start_plot() override;
|
||||
|
||||
// RRC interface
|
||||
bool set_config(const srsran::phy_cfg_nr_t& cfg) override;
|
||||
|
||||
// MAC interface
|
||||
int tx_request(const tx_request_t& request) override;
|
||||
int set_ul_grant(std::array<uint8_t, SRSRAN_RAR_UL_GRANT_NBITS>, uint16_t rnti, srsran_rnti_type_t rnti_type) override
|
||||
{
|
||||
return SRSRAN_SUCCESS;
|
||||
};
|
||||
void send_prach(const uint32_t preamble_idx,
|
||||
const int prach_occasion,
|
||||
const float target_power_dbm,
|
||||
const float ta_base_sec = 0.0f) override{};
|
||||
bool has_valid_sr_resource(uint32_t sr_id) override;
|
||||
void clear_pending_grants() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<srsran::srsran_basic_vnf> vnf;
|
||||
|
||||
srsue::stack_interface_phy_nr* stack = nullptr;
|
||||
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
#endif // SRSUE_VNF_PHY_NR_H
|
@ -1,82 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "srsran/common/basic_vnf_api.h"
|
||||
#include "srsran/common/test_common.h"
|
||||
#include "srsran/common/threads.h"
|
||||
#include "srsue/hdr/phy/vnf_phy_nr.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace srsue {
|
||||
|
||||
vnf_phy_nr::~vnf_phy_nr()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
int vnf_phy_nr::init(const srsue::phy_args_t& args_, srsue::stack_interface_phy_nr* stack_)
|
||||
{
|
||||
stack = stack_;
|
||||
return init(args_);
|
||||
}
|
||||
|
||||
int vnf_phy_nr::init(const srsue::phy_args_t& args_)
|
||||
{
|
||||
// create VNF
|
||||
vnf = std::unique_ptr<srsran::srsran_basic_vnf>(new srsran::srsran_basic_vnf(args_.vnf_args, stack));
|
||||
initialized = true;
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
void vnf_phy_nr::set_earfcn(std::vector<uint32_t> earfcns) {}
|
||||
|
||||
void vnf_phy_nr::stop()
|
||||
{
|
||||
if (initialized) {
|
||||
vnf->stop();
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Start GUI
|
||||
void vnf_phy_nr::start_plot() {}
|
||||
|
||||
void vnf_phy_nr::wait_initialize() {}
|
||||
|
||||
void vnf_phy_nr::get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) {}
|
||||
|
||||
int vnf_phy_nr::tx_request(const tx_request_t& request)
|
||||
{
|
||||
// send Tx request over basic API
|
||||
return vnf->tx_request(request);
|
||||
}
|
||||
bool vnf_phy_nr::set_config(const srsran::phy_cfg_nr_t& cfg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool vnf_phy_nr::has_valid_sr_resource(uint32_t sr_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void vnf_phy_nr::clear_pending_grants() {}
|
||||
|
||||
} // namespace srsue
|
Loading…
Reference in New Issue