diff --git a/lib/src/common/mac_pcap_net.cc b/lib/src/common/mac_pcap_net.cc index 45bc488c7..3b098be7b 100644 --- a/lib/src/common/mac_pcap_net.cc +++ b/lib/src/common/mac_pcap_net.cc @@ -44,6 +44,11 @@ uint32_t mac_pcap_net::open(std::string client_ip_addr_, return SRSLTE_ERROR; } + logger.info("Sending MAC PCAP frames to %s:%d (from %s:%d)", + client_ip_addr_.c_str(), + client_udp_port_, + bind_addr_str.c_str(), + bind_udp_port_); client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = inet_addr(client_ip_addr_.c_str()); client_addr.sin_port = htons(client_udp_port_); @@ -112,11 +117,6 @@ void mac_pcap_net::write_mac_lte_pdu_to_net(pcap_pdu_t& pdu) return; } - if (pdu.pdu.get()->get_headroom() < offset) { - logger.error("PDU headroom is to small for adding context buffer"); - return; - } - pdu.pdu.get()->msg -= offset; memcpy(pdu.pdu.get()->msg, buffer, offset); pdu.pdu.get()->N_bytes += offset; @@ -128,8 +128,9 @@ void mac_pcap_net::write_mac_lte_pdu_to_net(pcap_pdu_t& pdu) (const struct sockaddr*)&client_addr, sizeof(client_addr)); - if ((int)pdu.pdu.get()->N_bytes != bytes_sent) { - logger.error("Sending UDP packet mismatches %d != %d", pdu.pdu.get()->N_bytes, bytes_sent); + if ((int)pdu.pdu.get()->N_bytes != bytes_sent || bytes_sent < 0) { + logger.error( + "Sending UDP packet mismatches %d != %d (err %s)", pdu.pdu.get()->N_bytes, bytes_sent, strerror(errno)); } } @@ -161,8 +162,9 @@ void mac_pcap_net::write_mac_nr_pdu_to_net(pcap_pdu_t& pdu) (const struct sockaddr*)&client_addr, sizeof(client_addr)); - if ((int)pdu.pdu.get()->N_bytes != bytes_sent) { - logger.error("Sending UDP packet mismatches %d != %d", pdu.pdu.get()->N_bytes, bytes_sent); + if ((int)pdu.pdu.get()->N_bytes != bytes_sent || bytes_sent < 0) { + logger.error( + "Sending UDP packet mismatches %d != %d (err %s)", pdu.pdu.get()->N_bytes, bytes_sent, strerror(errno)); } } } // namespace srslte \ No newline at end of file diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index c6098856e..7b700858f 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -83,11 +83,15 @@ rx_gain = 40 ##################################################################### # Packet capture configuration # -# MAC Packets are captured to file in the compact format decoded by -# the Wireshark mac-lte-framed dissector and with DLT 147. -# To use the dissector, edit the preferences for DLT_USER to -# add an entry with DLT=147, Payload Protocol=mac-lte-framed. +# MAC-layer packets are captured to file a the compact format decoded +# by the Wireshark. For decoding, use the UDP dissector and the UDP +# heuristic dissection. Edit the preferences (Edit > Preferences > +# Protocols > DLT_USER) for DLT_USER to add an entry for DLT=149 with +# Protocol=udp. Further, enable the heuristic dissection in UDP under: +# Analyze > Enabled Protocols > MAC-LTE > mac_lte_udp and MAC-NR > mac_nr_udp # For more information see: https://wiki.wireshark.org/MAC-LTE +# Configuring this Wireshark preferences is needed for decoding the MAC PCAP +# files as well as for the live network capture option. # # Please note that this setting will by default only capture MAC # frames on dedicated channels, and not SIB. You have to build with @@ -104,6 +108,11 @@ rx_gain = 40 # s1ap_enable: Enable or disable the PCAP. # s1ap_filename: File name where to save the PCAP. # +# mac_net_enable: Enable MAC layer packet captures sent over the network (true/false default: false) +# bind_ip: Bind IP address for MAC network trace (default: "0.0.0.0") +# bind_port: Bind port for MAC network trace (default: 5687) +# client_ip: Client IP address for MAC network trace (default "127.0.0.1") +# client_port Client IP address for MAC network trace (default: 5847) ##################################################################### [pcap] enable = false @@ -111,6 +120,12 @@ filename = /tmp/enb.pcap s1ap_enable = false s1ap_filename = /tmp/enb_s1ap.pcap +mac_net_enable = false +bind_ip = 0.0.0.0 +bind_port = 5687 +client_ip = 127.0.0.1 +client_port = 5847 + ##################################################################### # Log configuration # diff --git a/srsenb/hdr/stack/enb_stack_base.h b/srsenb/hdr/stack/enb_stack_base.h index a78a80283..20427f712 100644 --- a/srsenb/hdr/stack/enb_stack_base.h +++ b/srsenb/hdr/stack/enb_stack_base.h @@ -26,6 +26,14 @@ typedef struct { std::string filename; } pcap_args_t; +typedef struct { + bool enable; + std::string client_ip; + std::string bind_ip; + uint16_t client_port; + uint16_t bind_port; +} pcap_net_args_t; + typedef struct { bool enable; std::string m1u_multiaddr; @@ -65,6 +73,7 @@ typedef struct { mac_args_t mac; s1ap_args_t s1ap; pcap_args_t mac_pcap; + pcap_net_args_t mac_pcap_net; pcap_args_t s1ap_pcap; stack_log_args_t log; embms_args_t embms; diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index 83f0f6afe..93c1a6650 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -27,6 +27,7 @@ #include "upper/s1ap.h" #include "enb_stack_base.h" +#include "srslte/common/mac_pcap_net.h" #include "srslte/interfaces/enb_interfaces.h" #include "srslte/srslog/srslog.h" @@ -125,6 +126,11 @@ private: srslog::basic_logger& gtpu_logger; srslog::basic_logger& stack_logger; + // PCAP and trace option + srslte::mac_pcap mac_pcap; + srslte::mac_pcap_net mac_pcap_net; + srslte::s1ap_pcap s1ap_pcap; + // task handling srslte::task_scheduler task_sched; srslte::task_queue_handle enb_task_queue, gtpu_task_queue, mme_task_queue, sync_task_queue; @@ -132,14 +138,12 @@ private: // components that layers depend on (need to be destroyed after layers) std::unique_ptr rx_sockets; - srsenb::mac mac; - srslte::mac_pcap mac_pcap; - srsenb::rlc rlc; - srsenb::pdcp pdcp; - srsenb::rrc rrc; - srsenb::gtpu gtpu; - srsenb::s1ap s1ap; - srslte::s1ap_pcap s1ap_pcap; + srsenb::mac mac; + srsenb::rlc rlc; + srsenb::pdcp pdcp; + srsenb::rrc rrc; + srsenb::gtpu gtpu; + srsenb::s1ap s1ap; srslte::logger* logger = nullptr; diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 693fe3911..e6c2ee4a2 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -17,6 +17,7 @@ #include "srsenb/hdr/stack/mac/schedulers/sched_time_rr.h" #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" +#include "srslte/common/mac_pcap_net.h" #include "srslte/common/task_scheduler.h" #include "srslte/common/threads.h" #include "srslte/common/tti_sync_cv.h" @@ -45,6 +46,7 @@ public: void stop(); void start_pcap(srslte::mac_pcap* pcap_); + void start_pcap_net(srslte::mac_pcap_net* pcap_net_); /******** Interface from PHY (PHY -> MAC) ****************/ int sr_detected(uint32_t tti, uint16_t rnti) final; @@ -174,7 +176,8 @@ private: uint8_t mtch_payload_buffer[mtch_payload_len] = {}; // pointer to MAC PCAP object - srslte::mac_pcap* pcap = nullptr; + srslte::mac_pcap* pcap = nullptr; + srslte::mac_pcap_net* pcap_net = nullptr; // Number of rach preambles detected for a cc. std::vector detected_rachs; diff --git a/srsenb/hdr/stack/mac/ue.h b/srsenb/hdr/stack/mac/ue.h index 47bc8f679..887e1f6f4 100644 --- a/srsenb/hdr/stack/mac/ue.h +++ b/srsenb/hdr/stack/mac/ue.h @@ -18,6 +18,7 @@ #include "srslte/common/block_queue.h" #include "srslte/common/log.h" #include "srslte/common/mac_pcap.h" +#include "srslte/common/mac_pcap_net.h" #include "srslte/interfaces/sched_interface.h" #include "srslte/mac/pdu.h" #include "srslte/mac/pdu_queue.h" @@ -90,9 +91,9 @@ public: uint32_t nof_tx_harq_proc = SRSLTE_FDD_NOF_HARQ); virtual ~ue(); - void reset(); void start_pcap(srslte::mac_pcap* pcap_); + void start_pcap_net(srslte::mac_pcap_net* pcap_net_); void set_tti(uint32_t tti); uint16_t get_rnti() { return rnti; } uint32_t set_ta(int ta) override; @@ -142,14 +143,15 @@ private: uint32_t dl_pmi_counter = 0; mac_ue_metrics_t ue_metrics = {}; - srslte::mac_pcap* pcap = nullptr; - uint64_t conres_id = 0; - uint16_t rnti = 0; - uint32_t nof_prb = 0; - uint32_t last_tti = 0; - uint32_t nof_failures = 0; - int nof_rx_harq_proc = 0; - int nof_tx_harq_proc = 0; + srslte::mac_pcap* pcap = nullptr; + srslte::mac_pcap_net* pcap_net = nullptr; + uint64_t conres_id = 0; + uint16_t rnti = 0; + uint32_t nof_prb = 0; + uint32_t last_tti = 0; + uint32_t nof_failures = 0; + int nof_rx_harq_proc = 0; + int nof_tx_harq_proc = 0; std::vector cc_buffers; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index c736175e9..92da8e75b 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -131,6 +131,11 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("pcap.filename", bpo::value(&args->stack.mac_pcap.filename)->default_value("enb_mac.pcap"), "MAC layer capture filename") ("pcap.s1ap_enable", bpo::value(&args->stack.s1ap_pcap.enable)->default_value(false), "Enable S1AP packet captures for wireshark") ("pcap.s1ap_filename", bpo::value(&args->stack.s1ap_pcap.filename)->default_value("enb_s1ap.pcap"), "S1AP layer capture filename") + ("pcap.mac_net_enable", bpo::value(&args->stack.mac_pcap_net.enable)->default_value(false), "Enable MAC network captures") + ("pcap.bind_ip", bpo::value(&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(&args->stack.mac_pcap_net.bind_port)->default_value(5687), "Bind port for MAC network trace") + ("pcap.client_ip", bpo::value(&args->stack.mac_pcap_net.client_ip)->default_value("127.0.0.1"), "Client IP address for MAC network trace") + ("pcap.client_port", bpo::value(&args->stack.mac_pcap_net.client_port)->default_value(5847), "Enable MAC network captures") /* Scheduling section */ ("scheduler.policy", bpo::value(&args->stack.mac.sched.sched_policy)->default_value("time_pf"), "DL and UL data scheduling policy (E.g. time_rr, time_pf)") diff --git a/srsenb/src/stack/enb_stack_lte.cc b/srsenb/src/stack/enb_stack_lte.cc index 1414e7496..237e2d1df 100644 --- a/srsenb/src/stack/enb_stack_lte.cc +++ b/srsenb/src/stack/enb_stack_lte.cc @@ -109,6 +109,15 @@ int enb_stack_lte::init(const stack_args_t& args_, const rrc_cfg_t& rrc_cfg_) mac_pcap.open(args.mac_pcap.filename.c_str()); mac.start_pcap(&mac_pcap); } + + if (args.mac_pcap_net.enable) { + mac_pcap_net.open(args.mac_pcap_net.client_ip, + args.mac_pcap_net.bind_ip, + args.mac_pcap_net.client_port, + args.mac_pcap_net.bind_port); + mac.start_pcap_net(&mac_pcap_net); + } + if (args.s1ap_pcap.enable) { s1ap_pcap.open(args.s1ap_pcap.filename.c_str()); s1ap.start_pcap(&s1ap_pcap); @@ -182,6 +191,11 @@ void enb_stack_lte::stop_impl() if (args.mac_pcap.enable) { mac_pcap.close(); } + + if (args.mac_pcap_net.enable) { + mac_pcap_net.close(); + } + if (args.s1ap_pcap.enable) { s1ap_pcap.close(); } diff --git a/srsenb/src/stack/mac/mac.cc b/srsenb/src/stack/mac/mac.cc index 4075118ad..062098bed 100644 --- a/srsenb/src/stack/mac/mac.cc +++ b/srsenb/src/stack/mac/mac.cc @@ -21,7 +21,7 @@ #include "srslte/interfaces/enb_rlc_interfaces.h" #include "srslte/interfaces/enb_rrc_interfaces.h" -//#define WRITE_SIB_PCAP +#define WRITE_SIB_PCAP using namespace asn1::rrc; namespace srsenb { @@ -122,6 +122,15 @@ void mac::start_pcap(srslte::mac_pcap* pcap_) } } +void mac::start_pcap_net(srslte::mac_pcap_net* pcap_net_) +{ + pcap_net = pcap_net_; + // Set pcap in all UEs for UL messages + for (auto& u : ue_db) { + u.second->start_pcap_net(pcap_net); + } +} + /******************************************************** * * RLC interface @@ -460,6 +469,10 @@ uint16_t mac::allocate_ue() ue_ptr->start_pcap(pcap); } + if (pcap_net != nullptr) { + ue_ptr->start_pcap_net(pcap_net); + } + { srslte::rwlock_write_guard lock(rwlock); ue_db[rnti] = std::move(ue_ptr); @@ -613,6 +626,10 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) pcap->write_dl_crnti( dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); } + if (pcap_net) { + pcap_net->write_dl_crnti( + dl_sched_res->pdsch[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti_tx_dl, enb_cc_idx); + } } else { /* TB not enabled OR no data to send: set pointers to NULL */ dl_sched_res->pdsch[n].data[tb] = nullptr; @@ -657,7 +674,14 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) tti_tx_dl, enb_cc_idx); } - + if (pcap_net) { + pcap_net->write_dl_ranti(dl_sched_res->pdsch[n].data[0], + sched_result.rar[i].tbs, + dl_sched_res->pdsch[n].dci.rnti, + true, + tti_tx_dl, + enb_cc_idx); + } n++; } @@ -675,6 +699,10 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) if (pcap) { pcap->write_dl_sirnti(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); } + if (pcap_net) { + pcap_net->write_dl_sirnti( + dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); + } #endif } else { dl_sched_res->pdsch[n].softbuffer_tx[0] = &common_buffers[enb_cc_idx].pcch_softbuffer_tx; @@ -684,6 +712,9 @@ int mac::get_dl_sched(uint32_t tti_tx_dl, dl_sched_list_t& dl_sched_res_list) if (pcap) { pcap->write_dl_pch(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); } + if (pcap_net) { + pcap_net->write_dl_pch(dl_sched_res->pdsch[n].data[0], sched_result.bc[i].tbs, true, tti_tx_dl, enb_cc_idx); + } } n++; diff --git a/srsenb/src/stack/mac/ue.cc b/srsenb/src/stack/mac/ue.cc index ae44c0ee4..3c0c6e0f6 100644 --- a/srsenb/src/stack/mac/ue.cc +++ b/srsenb/src/stack/mac/ue.cc @@ -147,6 +147,11 @@ void ue::reset() } } +void ue::start_pcap_net(srslte::mac_pcap_net* pcap_net_) +{ + pcap_net = pcap_net_; +} + void ue::start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; @@ -256,6 +261,10 @@ void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channe pcap->write_ul_crnti(pdu, nof_bytes, rnti, true, last_tti, UL_CC_IDX); } + if (pcap_net) { + pcap_net->write_ul_crnti(pdu, nof_bytes, rnti, true, last_tti, UL_CC_IDX); + } + pdus.deallocate(pdu); uint32_t lcid_most_data = 0;