Added option to save NGAP pcaps.

master
Pedro Alvarez 3 years ago
parent a4e3d6144f
commit 5e22e42762

@ -0,0 +1,43 @@
/**
*
* \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_NGAP_PCAP_H
#define SRSRAN_NGAP_PCAP_H
#include "srsran/common/pcap.h"
#include <string>
namespace srsran {
class ngap_pcap
{
public:
ngap_pcap();
ngap_pcap(const ngap_pcap& other) = delete;
ngap_pcap& operator=(const ngap_pcap& other) = delete;
ngap_pcap(ngap_pcap&& other) = delete;
ngap_pcap& operator=(ngap_pcap&& other) = delete;
void enable();
void open(const char* filename_);
void close();
void write_ngap(uint8_t* pdu, uint32_t pdu_len_bytes);
private:
bool enable_write = false;
std::string filename;
FILE* pcap_file = nullptr;
};
} // namespace srsran
#endif // SRSRAN_NAS_PCAP_H

@ -24,6 +24,7 @@
#define UDP_DLT 149 // UDP needs to be selected as protocol
#define S1AP_LTE_DLT 150
#define NAS_5G_DLT 151
#define NGAP_5G_DLT 152
/* This structure gets written to the start of the file */
typedef struct pcap_hdr_s {
@ -180,6 +181,12 @@ typedef struct S1AP_Context_Info_s {
unsigned char dummy;
} S1AP_Context_Info_t;
/* Context information for every S1AP PDU that will be logged */
typedef struct NGAP_Context_Info_s {
// No Context yet
unsigned char dummy;
} NGAP_Context_Info_t;
#ifdef __cplusplus
extern "C" {
#endif
@ -204,6 +211,9 @@ int LTE_PCAP_RLC_WritePDU(FILE* fd, RLC_Context_Info_t* context, const unsigned
/* Write an individual S1AP PDU (PCAP packet header + s1ap-context + s1ap-pdu) */
int LTE_PCAP_S1AP_WritePDU(FILE* fd, S1AP_Context_Info_t* context, const unsigned char* PDU, unsigned int length);
/* Write an individual S1AP PDU (PCAP packet header + s1ap-context + s1ap-pdu) */
int LTE_PCAP_NGAP_WritePDU(FILE* fd, NGAP_Context_Info_t* context, const unsigned char* PDU, unsigned int length);
/* Write an individual NR MAC PDU (PCAP packet header + UDP header + nr-mac-context + mac-pdu) */
int NR_PCAP_MAC_UDP_WritePDU(FILE* fd, mac_nr_context_info_t* context, const unsigned char* PDU, unsigned int length);
int NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(mac_nr_context_info_t* context, uint8_t* buffer, unsigned int length);

@ -27,6 +27,7 @@ set(SOURCES arch_select.cc
rrc_common.cc
rlc_pcap.cc
s1ap_pcap.cc
ngap_pcap.cc
security.cc
standard_streams.cc
thread_pool.cc

@ -0,0 +1,61 @@
/**
*
* \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/ngap_pcap.h"
#include "srsran/common/pcap.h"
#include "srsran/srsran.h"
#include "srsran/support/emergency_handlers.h"
#include <stdint.h>
namespace srsran {
/// Try to flush the contents of the pcap class before the application is killed.
static void emergency_cleanup_handler(void* data)
{
reinterpret_cast<ngap_pcap*>(data)->close();
}
ngap_pcap::ngap_pcap()
{
add_emergency_cleanup_handler(emergency_cleanup_handler, this);
}
void ngap_pcap::enable()
{
enable_write = true;
}
void ngap_pcap::open(const char* filename_)
{
filename = filename_;
pcap_file = DLT_PCAP_Open(NGAP_5G_DLT, filename.c_str());
enable_write = true;
}
void ngap_pcap::close()
{
if (!enable_write) {
return;
}
fprintf(stdout, "Saving NGAP PCAP file (DLT=%d) to %s\n", NGAP_5G_DLT, filename.c_str());
DLT_PCAP_Close(pcap_file);
}
void ngap_pcap::write_ngap(uint8_t* pdu, uint32_t pdu_len_bytes)
{
if (enable_write) {
NGAP_Context_Info_t context;
if (pdu) {
LTE_PCAP_NGAP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes);
}
}
}
} // namespace srsran

@ -336,6 +336,34 @@ int LTE_PCAP_S1AP_WritePDU(FILE* fd, S1AP_Context_Info_t* context, const unsigne
return 1;
}
/* Write an individual PDU (PCAP packet header + s1ap-context + s1ap-pdu) */
int LTE_PCAP_NGAP_WritePDU(FILE* fd, NGAP_Context_Info_t* context, const unsigned char* PDU, unsigned int length)
{
pcaprec_hdr_t packet_header;
/* Can't write if file wasn't successfully opened */
if (fd == NULL) {
printf("Error: Can't write to empty file handle\n");
return 0;
}
/****************************************************************/
/* PCAP Header */
struct timeval t;
gettimeofday(&t, NULL);
packet_header.ts_sec = t.tv_sec;
packet_header.ts_usec = t.tv_usec;
packet_header.incl_len = length;
packet_header.orig_len = length;
/***************************************************************/
/* Now write everything to the file */
fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd);
fwrite(PDU, 1, length, fd);
return 1;
}
/**************************************************************************
* API functions for writing MAC-NR PCAP files *
**************************************************************************/

@ -137,6 +137,8 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("pcap.nr_filename", bpo::value<string>(&args->nr_stack.mac.pcap.filename)->default_value("/tmp/enb_mac_nr.pcap"), "NR MAC layer capture filename")
("pcap.s1ap_enable", bpo::value<bool>(&args->stack.s1ap_pcap.enable)->default_value(false), "Enable S1AP packet captures for wireshark")
("pcap.s1ap_filename", bpo::value<string>(&args->stack.s1ap_pcap.filename)->default_value("/tmp/enb_s1ap.pcap"), "S1AP layer capture filename")
("pcap.ngap_enable", bpo::value<bool>(&args->nr_stack.ngap_pcap.enable)->default_value(false), "Enable NGAP packet captures for wireshark")
("pcap.ngap_filename", bpo::value<string>(&args->nr_stack.ngap_pcap.filename)->default_value("/tmp/enb_ngap.pcap"), "NGAP layer capture filename")
("pcap.mac_net_enable", bpo::value<bool>(&args->stack.mac_pcap_net.enable)->default_value(false), "Enable MAC network captures")
("pcap.bind_ip", bpo::value<string>(&args->stack.mac_pcap_net.bind_ip)->default_value("0.0.0.0"), "Bind IP address for MAC network trace")
("pcap.bind_port", bpo::value<uint16_t>(&args->stack.mac_pcap_net.bind_port)->default_value(5687), "Bind port for MAC network trace")
@ -260,6 +262,14 @@ void parse_args(all_args_t* args, int argc, char* argv[])
("scheduler.nr_pusch_mcs", bpo::value<int>(&args->nr_stack.mac.sched_cfg.fixed_ul_mcs)->default_value(28), "Fixed NR UL MCS (-1 for dynamic).")
("expert.nr_pusch_max_its", bpo::value<uint32_t>(&args->phy.nr_pusch_max_its)->default_value(10), "Maximum number of LDPC iterations for NR.")
//NGAP section
("gnb.enb_id", bpo::value<uint32_t>(&args->nr_stack.ngap.gnb_id)->default_value(0), "gNodeB ID")
("gnb.name", bpo::value<string>(&args->nr_stack.ngap.gnb_name)->default_value("srsgnb01"), "gNodeB Name")
("gnb.amf_addr", bpo::value<string>(&args->nr_stack.ngap.amf_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connection")
("gnb.gtp_bind_addr", bpo::value<string>(&args->nr_stack.ngap.gtp_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for GTP connection")
("gnb.gtp_advertise_addr", bpo::value<string>(&args->nr_stack.ngap.gtp_advertise_addr)->default_value(""), "IP address of eNB to advertise for DL GTP-U Traffic")
("gnb.ngc_bind_addr", bpo::value<string>(&args->nr_stack.ngap.ngc_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection")
// VNF params
("vnf.type", bpo::value<string>(&args->phy.vnf_args.type)->default_value("gnb"), "VNF instance type [gnb,ue].")
("vnf.addr", bpo::value<string>(&args->phy.vnf_args.bind_addr)->default_value("localhost"), "Address to bind VNF interface.")
@ -336,6 +346,12 @@ void parse_args(all_args_t* args, int argc, char* argv[])
if (!srsran::string_to_mnc(mnc, &args->stack.s1ap.mnc)) {
cout << "Error parsing enb.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
if (!srsran::string_to_mcc(mcc, &args->nr_stack.ngap.mcc)) {
cout << "Error parsing enb.mcc:" << mcc << " - must be a 3-digit string." << endl;
}
if (!srsran::string_to_mnc(mnc, &args->nr_stack.ngap.mnc)) {
cout << "Error parsing enb.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
if (args->stack.embms.enable) {
if (args->stack.mac.sched.max_nof_ctrl_symbols == 3) {

@ -27,6 +27,8 @@
#include "srsenb/hdr/stack/enb_stack_base.h"
#include "srsran/interfaces/gnb_interfaces.h"
#include "srsran/common/ngap_pcap.h"
namespace srsenb {
class ngap;
@ -36,6 +38,7 @@ struct gnb_stack_args_t {
stack_log_args_t log;
mac_nr_args_t mac;
ngap_args_t ngap;
pcap_args_t ngap_pcap;
};
class gnb_stack_nr final : public srsenb::enb_stack_base,
@ -129,6 +132,8 @@ private:
srslog::basic_logger& gtpu_logger;
srslog::basic_logger& stack_logger;
srsran::ngap_pcap ngap_pcap;
// task scheduling
static const int STACK_MAIN_THREAD_PRIO = 4;
srsran::task_scheduler task_sched;

@ -22,6 +22,7 @@
#include "srsran/common/buffer_pool.h"
#include "srsran/common/common.h"
#include "srsran/common/network_utils.h"
#include "srsran/common/ngap_pcap.h"
#include "srsran/common/stack_procedure.h"
#include "srsran/common/standard_streams.h"
#include "srsran/common/task_scheduler.h"
@ -70,10 +71,13 @@ public:
// Stack interface
bool
handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags);
handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags);
void get_metrics(ngap_metrics_t& m);
void get_args(ngap_args_t& args_);
// PCAP
void start_pcap(srsran::ngap_pcap* pcap_);
private:
static const int AMF_PORT = 38412;
static const int ADDR_FAMILY = AF_INET;
@ -128,6 +132,9 @@ private:
// TS 38.413 - Section 9.2.1.1 - PDU Session Resource Setup Request
bool handle_ue_pdu_session_res_setup_request(const asn1::ngap_nr::pdu_session_res_setup_request_s& msg);
// PCAP
srsran::ngap_pcap* pcap = nullptr;
class user_list
{
public:

@ -104,6 +104,11 @@ int gnb_stack_nr::init(const gnb_stack_args_t& args_,
gtpu_args.mme_addr = args.ngap.amf_addr;
gtpu_args.gtp_bind_addr = args.ngap.gtp_bind_addr;
gtpu->init(gtpu_args, &pdcp);
if (args.ngap_pcap.enable) {
ngap_pcap.open(args.ngap_pcap.filename.c_str());
ngap->start_pcap(&ngap_pcap);
}
}
// TODO: add SDAP

@ -371,11 +371,10 @@ bool ngap::handle_amf_rx_msg(srsran::unique_byte_buffer_t pdu,
bool ngap::handle_ngap_rx_pdu(srsran::byte_buffer_t* pdu)
{
// TODO:
// Save message to PCAP
// if (pcap != nullptr) {
// pcap->write_ngap(pdu->msg, pdu->N_bytes);
// }
if (pcap != nullptr) {
pcap->write_ngap(pdu->msg, pdu->N_bytes);
}
ngap_pdu_c rx_pdu;
asn1::cbit_ref bref(pdu->msg, pdu->N_bytes);
@ -696,6 +695,11 @@ bool ngap::sctp_send_ngap_pdu(const asn1::ngap_nr::ngap_pdu_c& tx_pdu, uint32_t
}
buf->N_bytes = bref.distance_bytes();
// Save message to PCAP
if (pcap != nullptr) {
pcap->write_ngap(buf->msg, buf->N_bytes);
}
if (rnti != SRSRAN_INVALID_RNTI) {
logger.info(buf->msg, buf->N_bytes, "Tx NGAP SDU, %s, rnti=0x%x", procedure_name, rnti);
} else {
@ -794,4 +798,11 @@ std::string ngap::get_cause(const cause_c& c)
return cause;
}
/*
* PCAP
*/
void ngap::start_pcap(srsran::ngap_pcap* pcap_)
{
pcap = pcap_;
}
} // namespace srsenb

Loading…
Cancel
Save