mirror of https://github.com/PentHertz/srsLTE.git
Added mac pcap network class that dumps the packets to a udp network sink
This commit is contained in:
parent
a58f0642cb
commit
894e4d3501
|
@ -28,10 +28,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu);
|
void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu);
|
||||||
|
void run_thread() final;
|
||||||
|
|
||||||
FILE* pcap_file = nullptr;
|
FILE* pcap_file = nullptr;
|
||||||
uint32_t dlt = 0; // The DLT used for the PCAP file
|
uint32_t dlt = 0; // The DLT used for the PCAP file
|
||||||
std::string filename;
|
std::string filename;
|
||||||
void run_thread() final;
|
|
||||||
};
|
};
|
||||||
} // namespace srslte
|
} // namespace srslte
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2020 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 SRSLTE_MAC_PCAP_NET_H
|
||||||
|
#define SRSLTE_MAC_PCAP_NET_H
|
||||||
|
|
||||||
|
#include "srslte/common/common.h"
|
||||||
|
#include "srslte/common/mac_pcap_base.h"
|
||||||
|
#include "srslte/common/network_utils.h"
|
||||||
|
#include "srslte/srslte.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
class mac_pcap_net : public mac_pcap_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
mac_pcap_net();
|
||||||
|
~mac_pcap_net();
|
||||||
|
uint32_t open(std::string client_ip_addr_,
|
||||||
|
std::string bind_addr_str = "0.0.0.0",
|
||||||
|
uint16_t client_udp_port_ = 5847,
|
||||||
|
uint16_t bind_udp_port_ = 5687,
|
||||||
|
uint32_t ue_id_ = 0);
|
||||||
|
uint32_t close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void write_pdu(srslte::mac_pcap_base::pcap_pdu_t& pdu);
|
||||||
|
void write_mac_lte_pdu_to_net(srslte::mac_pcap_base::pcap_pdu_t& pdu);
|
||||||
|
void write_mac_nr_pdu_to_net(srslte::mac_pcap_base::pcap_pdu_t& pdu);
|
||||||
|
void run_thread() final;
|
||||||
|
|
||||||
|
srslte::socket_handler_t socket;
|
||||||
|
struct sockaddr_in client_addr;
|
||||||
|
};
|
||||||
|
} // namespace srslte
|
||||||
|
|
||||||
|
#endif // SRSLTE_MAC_PCAP_NET_H
|
|
@ -23,6 +23,7 @@ set(SOURCES arch_select.cc
|
||||||
mac_pcap_base.cc
|
mac_pcap_base.cc
|
||||||
nas_pcap.cc
|
nas_pcap.cc
|
||||||
network_utils.cc
|
network_utils.cc
|
||||||
|
mac_pcap_net.cc
|
||||||
pcap.c
|
pcap.c
|
||||||
rlc_pcap.cc
|
rlc_pcap.cc
|
||||||
s1ap_pcap.cc
|
s1ap_pcap.cc
|
||||||
|
@ -47,7 +48,7 @@ add_dependencies(srslte_common gen_build_info)
|
||||||
add_executable(arch_select arch_select.cc)
|
add_executable(arch_select arch_select.cc)
|
||||||
|
|
||||||
target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${BACKWARD_INCLUDE_DIRS})
|
target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${BACKWARD_INCLUDE_DIRS})
|
||||||
target_link_libraries(srslte_common srslte_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES})
|
target_link_libraries(srslte_common srslte_phy srslog ${SEC_LIBRARIES} ${BACKWARD_LIBRARIES} ${SCTP_LIBRARIES})
|
||||||
target_compile_definitions(srslte_common PRIVATE ${BACKWARD_DEFINITIONS})
|
target_compile_definitions(srslte_common PRIVATE ${BACKWARD_DEFINITIONS})
|
||||||
|
|
||||||
INSTALL(TARGETS srslte_common DESTINATION ${LIBRARY_DIR})
|
INSTALL(TARGETS srslte_common DESTINATION ${LIBRARY_DIR})
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2020 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 "srslte/common/mac_pcap_net.h"
|
||||||
|
|
||||||
|
namespace srslte {
|
||||||
|
|
||||||
|
mac_pcap_net::mac_pcap_net() : mac_pcap_base() {}
|
||||||
|
|
||||||
|
mac_pcap_net::~mac_pcap_net()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
uint32_t mac_pcap_net::open(std::string client_ip_addr_,
|
||||||
|
std::string bind_addr_str,
|
||||||
|
uint16_t client_udp_port_,
|
||||||
|
uint16_t bind_udp_port_,
|
||||||
|
uint32_t ue_id_)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
|
if (socket.is_init()) {
|
||||||
|
logger.error("PCAP socket writer for %s already running. Close first.", bind_addr_str.c_str());
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not socket.open_socket(
|
||||||
|
net_utils::addr_family::ipv4, net_utils::socket_type::datagram, net_utils::protocol_type::UDP)) {
|
||||||
|
logger.error("Couldn't open socket %s to write PCAP", bind_addr_str.c_str());
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
if (not socket.bind_addr(bind_addr_str.c_str(), bind_udp_port_)) {
|
||||||
|
socket.reset();
|
||||||
|
logger.error("Couldn't bind socket %s to write PCAP", bind_addr_str.c_str());
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_);
|
||||||
|
running = true;
|
||||||
|
ue_id = ue_id_;
|
||||||
|
// start writer thread
|
||||||
|
start();
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mac_pcap_net::close()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
if (running == false || socket.is_init() == false) {
|
||||||
|
return SRSLTE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell writer thread to stop
|
||||||
|
running = false;
|
||||||
|
pcap_pdu_t pdu = {};
|
||||||
|
queue.push(std::move(pdu));
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_thread_finish();
|
||||||
|
// close socket handle
|
||||||
|
if (socket.is_init()) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac_pcap_net::run_thread()
|
||||||
|
{
|
||||||
|
// blocking write until stopped
|
||||||
|
while (running) {
|
||||||
|
pcap_pdu_t pdu = queue.wait_pop();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
write_pdu(pdu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write remainder of queue
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
pcap_pdu_t pdu = {};
|
||||||
|
while (queue.try_pop(&pdu)) {
|
||||||
|
write_pdu(pdu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac_pcap_net::write_pdu(pcap_pdu_t& pdu)
|
||||||
|
{
|
||||||
|
if (pdu.pdu != nullptr && socket.is_init()) {
|
||||||
|
switch (pdu.rat) {
|
||||||
|
case srslte_rat_t::lte:
|
||||||
|
write_mac_lte_pdu_to_net(pdu);
|
||||||
|
break;
|
||||||
|
case srslte_rat_t::nr:
|
||||||
|
write_mac_nr_pdu_to_net(pdu);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.error("Error writing PDU to PCAP socket. Unsupported RAT selected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac_pcap_net::write_mac_lte_pdu_to_net(pcap_pdu_t& pdu)
|
||||||
|
{
|
||||||
|
int bytes_sent;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint8_t buffer[PCAP_CONTEXT_HEADER_MAX];
|
||||||
|
|
||||||
|
// MAC_LTE_START_STRING for UDP heuristics
|
||||||
|
memcpy(buffer + offset, MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING));
|
||||||
|
offset += strlen(MAC_LTE_START_STRING);
|
||||||
|
|
||||||
|
offset += LTE_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(&pdu.context, buffer + offset, PCAP_CONTEXT_HEADER_MAX);
|
||||||
|
|
||||||
|
if (pdu.pdu.get()->get_headroom() < offset) {
|
||||||
|
logger.error("PDU headroom is to small for adding context buffer");
|
||||||
|
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;
|
||||||
|
|
||||||
|
bytes_sent = sendto(socket.get_socket(),
|
||||||
|
pdu.pdu.get()->msg,
|
||||||
|
pdu.pdu.get()->N_bytes,
|
||||||
|
0,
|
||||||
|
(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac_pcap_net::write_mac_nr_pdu_to_net(pcap_pdu_t& pdu)
|
||||||
|
{
|
||||||
|
int bytes_sent;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint8_t buffer[PCAP_CONTEXT_HEADER_MAX];
|
||||||
|
|
||||||
|
// MAC_LTE_START_STRING for UDP heuristics
|
||||||
|
memcpy(buffer + offset, MAC_LTE_START_STRING, strlen(MAC_LTE_START_STRING));
|
||||||
|
offset += strlen(MAC_LTE_START_STRING);
|
||||||
|
|
||||||
|
offset += NR_PCAP_PACK_MAC_CONTEXT_TO_BUFFER(&pdu.context_nr, buffer + offset, PCAP_CONTEXT_HEADER_MAX);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
bytes_sent = sendto(socket.get_socket(),
|
||||||
|
pdu.pdu.get()->msg,
|
||||||
|
pdu.pdu.get()->N_bytes,
|
||||||
|
0,
|
||||||
|
(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace srslte
|
|
@ -88,3 +88,6 @@ target_link_libraries(pnf_dummy srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_
|
||||||
|
|
||||||
add_executable(pnf_bridge pnf_bridge.cc)
|
add_executable(pnf_bridge pnf_bridge.cc)
|
||||||
target_link_libraries(pnf_bridge srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
target_link_libraries(pnf_bridge srslte_common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
||||||
|
|
||||||
|
add_executable(mac_pcap_net_test mac_pcap_net_test.cc)
|
||||||
|
target_link_libraries(mac_pcap_net_test srslte_common ${SCTP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
|
@ -0,0 +1,115 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* \section COPYRIGHT
|
||||||
|
*
|
||||||
|
* Copyright 2013-2020 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 "srslte/common/common.h"
|
||||||
|
#include "srslte/common/mac_pcap_net.h"
|
||||||
|
#include "srslte/common/test_common.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// Write #num_pdus UL MAC PDUs using PCAP handle
|
||||||
|
void write_pcap_eutra_thread_function(srslte::mac_pcap_net* pcap_handle,
|
||||||
|
const std::array<uint8_t, 150>& pdu,
|
||||||
|
uint32_t num_pdus)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < num_pdus; i++) {
|
||||||
|
pcap_handle->write_ul_crnti(const_cast<uint8_t*>(pdu.data()), pdu.size(), 0x1001, true, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Finished thread " << std::this_thread::get_id() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write #num_pdus DL MAC NR PDUs using PCAP handle
|
||||||
|
void write_pcap_nr_thread_function(srslte::mac_pcap_net* pcap_handle,
|
||||||
|
const std::array<uint8_t, 11>& pdu,
|
||||||
|
uint32_t num_pdus)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < num_pdus; i++) {
|
||||||
|
pcap_handle->write_dl_crnti_nr(const_cast<uint8_t*>(pdu.data()), pdu.size(), 0x1001, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Finished thread " << std::this_thread::get_id() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
int lte_mac_pcap_net_test()
|
||||||
|
{
|
||||||
|
std::array<uint8_t, 150> tv = {
|
||||||
|
0x21, 0x08, 0x22, 0x80, 0x82, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||||
|
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
uint32_t num_threads = 10;
|
||||||
|
uint32_t num_pdus_per_thread = 100;
|
||||||
|
|
||||||
|
std::unique_ptr<srslte::mac_pcap_net> pcap_handle = std::unique_ptr<srslte::mac_pcap_net>(new srslte::mac_pcap_net());
|
||||||
|
TESTASSERT(pcap_handle->open("127.0.0.1") == SRSLTE_SUCCESS);
|
||||||
|
TESTASSERT(pcap_handle->open("127.0.0.1") != SRSLTE_SUCCESS); // open again will fail
|
||||||
|
|
||||||
|
std::vector<std::thread> writer_threads;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < num_threads; i++) {
|
||||||
|
writer_threads.push_back(std::thread(write_pcap_eutra_thread_function, pcap_handle.get(), tv, num_pdus_per_thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for threads to finish
|
||||||
|
for (std::thread& thread : writer_threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
TESTASSERT(pcap_handle->close() == SRSLTE_SUCCESS);
|
||||||
|
TESTASSERT(pcap_handle->close() != SRSLTE_SUCCESS); // closing twice will fail
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nr_mac_pcap_net_test()
|
||||||
|
{
|
||||||
|
std::array<uint8_t, 11> tv = {0x42, 0x00, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
|
||||||
|
|
||||||
|
uint32_t num_threads = 10;
|
||||||
|
uint32_t num_pdus_per_thread = 100;
|
||||||
|
|
||||||
|
std::unique_ptr<srslte::mac_pcap_net> pcap_handle = std::unique_ptr<srslte::mac_pcap_net>(new srslte::mac_pcap_net());
|
||||||
|
TESTASSERT(pcap_handle->open("127.0.0.1") == SRSLTE_SUCCESS);
|
||||||
|
TESTASSERT(pcap_handle->open("127.0.0.1") != SRSLTE_SUCCESS); // open again will fail
|
||||||
|
|
||||||
|
std::vector<std::thread> writer_threads;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < num_threads; i++) {
|
||||||
|
writer_threads.push_back(std::thread(write_pcap_nr_thread_function, pcap_handle.get(), tv, num_pdus_per_thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for threads to finish
|
||||||
|
for (std::thread& thread : writer_threads) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTASSERT(pcap_handle->close() == SRSLTE_SUCCESS);
|
||||||
|
TESTASSERT(pcap_handle->close() != SRSLTE_SUCCESS); // closing twice will fail
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
auto& mac_logger = srslog::fetch_basic_logger("MAC", false);
|
||||||
|
mac_logger.set_level(srslog::basic_levels::debug);
|
||||||
|
mac_logger.set_hex_dump_max_size(-1);
|
||||||
|
srslog::init();
|
||||||
|
|
||||||
|
TESTASSERT(lte_mac_pcap_net_test() == SRSLTE_SUCCESS);
|
||||||
|
TESTASSERT(nr_mac_pcap_net_test() == SRSLTE_SUCCESS);
|
||||||
|
}
|
Loading…
Reference in New Issue