|
| 1 | +/* |
| 2 | + * |
| 3 | + * Copyright 2021-2024 Software Radio Systems Limited |
| 4 | + * |
| 5 | + * By using this file, you agree to the terms and conditions set |
| 6 | + * forth in the LICENSE file which can be found at the top level of |
| 7 | + * the distribution. |
| 8 | + * |
| 9 | + */ |
| 10 | + |
| 11 | +#include "srsran/e1ap/gateways/e1_network_client_factory.h" |
| 12 | +#include "srsran/asn1/e1ap/e1ap.h" |
| 13 | +#include "srsran/e1ap/common/e1ap_message.h" |
| 14 | +#include "srsran/gateways/sctp_network_client_factory.h" |
| 15 | +#include "srsran/pcap/dlt_pcap.h" |
| 16 | +#include "srsran/support/io/io_broker.h" |
| 17 | + |
| 18 | +using namespace srsran; |
| 19 | + |
| 20 | +namespace { |
| 21 | + |
| 22 | +/// \brief Notifier for converting packed E1AP PDUs coming from the E1 GW into unpacked E1AP PDUs and forward them to |
| 23 | +/// the CU-UP. |
| 24 | +class sctp_to_e1_pdu_notifier final : public sctp_association_sdu_notifier |
| 25 | +{ |
| 26 | +public: |
| 27 | + sctp_to_e1_pdu_notifier(std::unique_ptr<e1ap_message_notifier> du_rx_pdu_notifier_, |
| 28 | + dlt_pcap& pcap_writer_, |
| 29 | + srslog::basic_logger& logger_) : |
| 30 | + du_rx_pdu_notifier(std::move(du_rx_pdu_notifier_)), pcap_writer(pcap_writer_), logger(logger_) |
| 31 | + { |
| 32 | + } |
| 33 | + |
| 34 | + bool on_new_sdu(byte_buffer sdu) override |
| 35 | + { |
| 36 | + // Unpack E1AP PDU. |
| 37 | + asn1::cbit_ref bref(sdu); |
| 38 | + e1ap_message msg; |
| 39 | + if (msg.pdu.unpack(bref) != asn1::SRSASN_SUCCESS) { |
| 40 | + logger.error("Couldn't unpack E1AP PDU"); |
| 41 | + return false; |
| 42 | + } |
| 43 | + |
| 44 | + // Forward Rx PDU to pcap, if enabled. |
| 45 | + if (pcap_writer.is_write_enabled()) { |
| 46 | + pcap_writer.push_pdu(sdu.copy()); |
| 47 | + } |
| 48 | + |
| 49 | + // Forward unpacked Rx PDU to the CU-UP. |
| 50 | + du_rx_pdu_notifier->on_new_message(msg); |
| 51 | + |
| 52 | + return true; |
| 53 | + } |
| 54 | + |
| 55 | +private: |
| 56 | + std::unique_ptr<e1ap_message_notifier> du_rx_pdu_notifier; |
| 57 | + dlt_pcap& pcap_writer; |
| 58 | + srslog::basic_logger& logger; |
| 59 | +}; |
| 60 | + |
| 61 | +/// \brief Notifier for converting unpacked E1AP PDUs coming from the CU-UP into packed E1AP PDUs and forward them to |
| 62 | +/// the F1C-GW. |
| 63 | +class e1_to_sctp_pdu_notifier final : public e1ap_message_notifier |
| 64 | +{ |
| 65 | +public: |
| 66 | + e1_to_sctp_pdu_notifier(std::unique_ptr<sctp_association_sdu_notifier> sctp_rx_pdu_notifier_, |
| 67 | + dlt_pcap& pcap_writer_, |
| 68 | + srslog::basic_logger& logger_) : |
| 69 | + sctp_rx_pdu_notifier(std::move(sctp_rx_pdu_notifier_)), pcap_writer(pcap_writer_), logger(logger_) |
| 70 | + { |
| 71 | + } |
| 72 | + |
| 73 | + void on_new_message(const e1ap_message& msg) override |
| 74 | + { |
| 75 | + // pack E1AP PDU into SCTP SDU. |
| 76 | + byte_buffer tx_sdu{byte_buffer::fallback_allocation_tag{}}; |
| 77 | + asn1::bit_ref bref(tx_sdu); |
| 78 | + if (msg.pdu.pack(bref) != asn1::SRSASN_SUCCESS) { |
| 79 | + logger.error("Failed to pack E1AP PDU"); |
| 80 | + return; |
| 81 | + } |
| 82 | + |
| 83 | + // Push Tx PDU to pcap. |
| 84 | + if (pcap_writer.is_write_enabled()) { |
| 85 | + pcap_writer.push_pdu(tx_sdu.copy()); |
| 86 | + } |
| 87 | + |
| 88 | + // Forward packed Tx PDU to SCTP gateway. |
| 89 | + sctp_rx_pdu_notifier->on_new_sdu(std::move(tx_sdu)); |
| 90 | + } |
| 91 | + |
| 92 | +private: |
| 93 | + std::unique_ptr<sctp_association_sdu_notifier> sctp_rx_pdu_notifier; |
| 94 | + dlt_pcap& pcap_writer; |
| 95 | + srslog::basic_logger& logger; |
| 96 | +}; |
| 97 | + |
| 98 | +class e1_sctp_gateway_client final : public srs_cu_up::e1_connection_client |
| 99 | +{ |
| 100 | +public: |
| 101 | + e1_sctp_gateway_client(const e1_du_sctp_gateway_config& params) : |
| 102 | + pcap_writer(params.pcap), broker(params.broker), sctp_params(params.sctp) |
| 103 | + { |
| 104 | + // Create SCTP network adapter. |
| 105 | + sctp_gateway = create_sctp_network_client(sctp_network_client_config{params.sctp, broker}); |
| 106 | + report_error_if_not(sctp_gateway != nullptr, "Failed to create SCTP gateway client.\n"); |
| 107 | + } |
| 108 | + |
| 109 | + std::unique_ptr<e1ap_message_notifier> |
| 110 | + handle_cu_up_connection_request(std::unique_ptr<e1ap_message_notifier> cu_up_rx_pdu_notifier) override |
| 111 | + { |
| 112 | + srsran_assert(cu_up_rx_pdu_notifier != nullptr, "CU-UP Rx PDU notifier is null"); |
| 113 | + |
| 114 | + logger.debug( |
| 115 | + "Establishing TNL connection to CU-CP ({}:{})...", sctp_params.connect_address, sctp_params.connect_port); |
| 116 | + std::unique_ptr<sctp_association_sdu_notifier> sctp_sender = sctp_gateway->connect_to( |
| 117 | + "CU-CP", |
| 118 | + sctp_params.connect_address, |
| 119 | + sctp_params.connect_port, |
| 120 | + std::make_unique<sctp_to_e1_pdu_notifier>(std::move(cu_up_rx_pdu_notifier), pcap_writer, logger)); |
| 121 | + if (sctp_sender == nullptr) { |
| 122 | + logger.error("Failed to establish E1 TNL connection to CU-CP on {}:{}.\n", |
| 123 | + sctp_params.connect_address, |
| 124 | + sctp_params.connect_port); |
| 125 | + return nullptr; |
| 126 | + } |
| 127 | + logger.info("{}: TNL connection to {} on {}:{} accepted", |
| 128 | + sctp_params.if_name, |
| 129 | + sctp_params.dest_name, |
| 130 | + sctp_params.connect_address, |
| 131 | + sctp_params.connect_port); |
| 132 | + fmt::print("{}: Connection to {} on {}:{} completed\n", |
| 133 | + sctp_params.if_name, |
| 134 | + sctp_params.dest_name, |
| 135 | + sctp_params.connect_address, |
| 136 | + sctp_params.connect_port); |
| 137 | + |
| 138 | + // Return the Tx PDU notifier to the CU-UP. |
| 139 | + return std::make_unique<e1_to_sctp_pdu_notifier>(std::move(sctp_sender), pcap_writer, logger); |
| 140 | + } |
| 141 | + |
| 142 | +private: |
| 143 | + dlt_pcap& pcap_writer; |
| 144 | + io_broker& broker; |
| 145 | + srsran::sctp_network_connector_config sctp_params; |
| 146 | + srslog::basic_logger& logger = srslog::fetch_basic_logger("CU-UP-E1"); |
| 147 | + |
| 148 | + // SCTP network gateway |
| 149 | + std::unique_ptr<sctp_network_client> sctp_gateway; |
| 150 | +}; |
| 151 | + |
| 152 | +} // namespace |
| 153 | + |
| 154 | +std::unique_ptr<srs_cu_up::e1_connection_client> |
| 155 | +srsran::create_e1_gateway_client(const e1_du_sctp_gateway_config& params) |
| 156 | +{ |
| 157 | + return std::make_unique<e1_sctp_gateway_client>(params); |
| 158 | +} |
0 commit comments