From 0a36e35f84e9f2b59ac0304d6dd27407a58f9b1a Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Thu, 8 Sep 2022 10:34:27 +0200 Subject: [PATCH 1/6] rrc: add T300 timer --- srsenb/hdr/stack/rrc/rrc_ue.h | 3 ++- srsenb/src/stack/rrc/rrc_ue.cc | 15 ++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 6a3a256773..8d1df78154 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -30,7 +30,8 @@ class rrc::ue enum activity_timeout_type_t { MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs UE_INACTIVITY_TIMEOUT, ///< UE inactivity timeout (usually bigger than reestablishment timeout) - MSG5_RX_TIMEOUT, ///< UE timeout for receiving RRCConnectionSetupComplete / RRCReestablishmentComplete + MSG5_RX_TIMEOUT_T300, ///< UE timeout for receiving RRCConnectionSetupComplete + MSG5_RX_TIMEOUT_T301, ///< UE timeout for receiving RRCReestablishmentComplete nulltype }; diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 67cc2b5578..23907aa31c 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -212,7 +212,8 @@ void rrc::ue::activity_timer_expired(const activity_timeout_type_t type) con_release_result = procedure_result_code::activity_timeout; break; case MSG3_RX_TIMEOUT: - case MSG5_RX_TIMEOUT: + case MSG5_RX_TIMEOUT_T300: + case MSG5_RX_TIMEOUT_T301: // MSG3 timeout, no need to notify S1AP, just remove UE parent->rem_user_thread(rnti); con_release_result = procedure_result_code::msg3_timeout; @@ -292,7 +293,10 @@ void rrc::ue::set_activity_timeout(activity_timeout_type_t type) case UE_INACTIVITY_TIMEOUT: deadline_ms = parent->cfg.inactivity_timeout_ms; break; - case MSG5_RX_TIMEOUT: + case MSG5_RX_TIMEOUT_T300: + deadline_ms = get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t300.to_number(); + break; + case MSG5_RX_TIMEOUT_T301: deadline_ms = get_ue_cc_cfg(UE_PCELL_CC_IDX)->sib2.ue_timers_and_consts.t301.to_number(); break; default: @@ -341,6 +345,7 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) case ul_dcch_msg_type_c::c1_c_::types::rrc_conn_setup_complete: save_ul_message(std::move(original_pdu)); handle_rrc_con_setup_complete(&ul_dcch_msg.msg.c1().rrc_conn_setup_complete(), std::move(pdu)); + set_activity_timeout(UE_INACTIVITY_TIMEOUT); set_activity(); break; case ul_dcch_msg_type_c::c1_c_::types::rrc_conn_reest_complete: @@ -420,7 +425,7 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) std::string rrc::ue::to_string(const activity_timeout_type_t& type) { - constexpr static const char* options[] = {"Msg3 reception", "UE inactivity", "UE reestablishment"}; + constexpr static const char* options[] = {"Msg3 reception", "UE inactivity", "UE establishment", "UE reestablishment"}; return srsran::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type); } @@ -474,7 +479,7 @@ void rrc::ue::handle_rrc_con_req(rrc_conn_request_s* msg) send_connection_setup(); state = RRC_STATE_WAIT_FOR_CON_SETUP_COMPLETE; - set_activity_timeout(UE_INACTIVITY_TIMEOUT); + set_activity_timeout(MSG5_RX_TIMEOUT_T300); } void rrc::ue::send_connection_setup() @@ -730,7 +735,7 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) parent->rem_user_thread(old_rnti); state = RRC_STATE_WAIT_FOR_CON_REEST_COMPLETE; - set_activity_timeout(MSG5_RX_TIMEOUT); + set_activity_timeout(MSG5_RX_TIMEOUT_T301); } void rrc::ue::send_connection_reest(uint8_t ncc) From ebefc73d0c2fa961552eeed750ddfac0268ae28e Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 29 Sep 2022 10:12:42 +0200 Subject: [PATCH 2/6] rf: print the cause of failed RF plugins to stdout --- lib/src/phy/rf/rf_imp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 1f754a4039..3974f74544 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -419,8 +419,9 @@ static int load_plugin(srsran_rf_plugin_t* rf_plugin) rf_plugin->dl_handle = dlopen(rf_plugin->plugin_name, RTLD_NOW); if (rf_plugin->dl_handle == NULL) { // Not an error, if loading failed due to missing dependencies. - // Mark this plugin as not available and return SUCCESS. - INFO("Failed to load RF plugin %s: %s", rf_plugin->plugin_name, dlerror()); + // Flag this plugin as not available and return SUCCESS. + // Note: as this function is called before log-level is configured, use plain printf for any messages < ERROR + printf("Skipping RF plugin %s: %s\n", rf_plugin->plugin_name, dlerror()); rf_plugin->rf_api = NULL; return SRSRAN_SUCCESS; } From 142bfd6ea8e9cef4a3b92aa1777d948e5cdf84e0 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 5 Apr 2022 16:00:51 +0100 Subject: [PATCH 3/6] lib,netutils: added extra logging for opening/closing socket. --- lib/src/common/network_utils.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/src/common/network_utils.cc b/lib/src/common/network_utils.cc index e6dc6a97bc..a2d9ed91ba 100644 --- a/lib/src/common/network_utils.cc +++ b/lib/src/common/network_utils.cc @@ -109,6 +109,7 @@ int open_socket(net_utils::addr_family ip_type, net_utils::socket_type socket_ty perror("Could not create socket\n"); return -1; } + srslog::fetch_basic_logger(LOGSERVICE).debug("Opened %s socket=%d", net_utils::protocol_to_string(protocol), fd); if (protocol == protocol_type::SCTP) { // Sets the data_io_event to be able to use sendrecv_info @@ -191,7 +192,12 @@ bool bind_addr(int fd, const sockaddr_in& addr_in) if (bind(fd, (struct sockaddr*)&addr_in, sizeof(addr_in)) != 0) { srslog::fetch_basic_logger(LOGSERVICE) - .error("Failed to bind on address %s: %s errno %d", get_ip(addr_in).c_str(), strerror(errno), errno); + .error("Failed to bind on address %s:%d. Socket=%d, strerror=%s, errno=%d", + get_ip(addr_in).c_str(), + get_port(addr_in), + fd, + strerror(errno), + errno); perror("bind()"); return false; } @@ -297,9 +303,15 @@ bool unique_socket::open_socket(net_utils::addr_family ip_type, void unique_socket::close() { if (sockfd >= 0) { - ::close(sockfd); + if (::close(sockfd) == -1) { + srslog::fetch_basic_logger(LOGSERVICE).error("Socket=%d could not be closed.", sockfd); + } else { + srslog::fetch_basic_logger(LOGSERVICE).debug("Socket=%d was closed.", sockfd); + } sockfd = -1; addr = {}; + } else { + srslog::fetch_basic_logger(LOGSERVICE).debug("Socket=%d could not be closed.", sockfd); } } From 08d03ee6e2f287232836d89b5cffca7cab03a488 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Tue, 5 Apr 2022 19:00:29 +0100 Subject: [PATCH 4/6] netutils,s1ap: split setting the SCTP options into different functions. Added option for SO_REUSE_ADDR. Removed sctp_init_socket function. --- lib/include/srsran/common/network_utils.h | 6 +- .../srsran/interfaces/enb_s1ap_interfaces.h | 1 + lib/src/common/network_utils.cc | 192 ++++++++++-------- lib/test/common/network_utils_test.cc | 30 ++- srsenb/src/main.cc | 1 + srsenb/src/stack/s1ap/s1ap.cc | 24 ++- srsgnb/src/stack/ngap/ngap.cc | 15 +- 7 files changed, 174 insertions(+), 95 deletions(-) diff --git a/lib/include/srsran/common/network_utils.h b/lib/include/srsran/common/network_utils.h index 8e3de4ac15..b167d5d2e8 100644 --- a/lib/include/srsran/common/network_utils.h +++ b/lib/include/srsran/common/network_utils.h @@ -74,10 +74,14 @@ class unique_socket std::string get_ip() const { return net_utils::get_ip(addr); } net_utils::socket_type get_family() const { return net_utils::get_addr_family(sockfd); } + bool open_socket(net_utils::addr_family ip, net_utils::socket_type socket_type, net_utils::protocol_type protocol); bool bind_addr(const char* bind_addr_str, int port); bool connect_to(const char* dest_addr_str, int dest_port, sockaddr_in* dest_sockaddr = nullptr); bool start_listen(); - bool open_socket(net_utils::addr_family ip, net_utils::socket_type socket_type, net_utils::protocol_type protocol); + bool reuse_addr(); + bool sctp_subscribe_to_events(); + bool sctp_set_rto_opts(); + bool sctp_set_init_msg_opts(); int get_socket() const { return sockfd; }; protected: diff --git a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h index b6b2a0741e..1ffd820267 100644 --- a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h +++ b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h @@ -29,6 +29,7 @@ struct s1ap_args_t { std::string gtp_advertise_addr; std::string s1c_bind_addr; uint16_t s1c_bind_port; + bool s1c_reuse_addr; std::string enb_name; uint32_t ts1_reloc_prep_timeout; uint32_t ts1_reloc_overall_timeout; diff --git a/lib/src/common/network_utils.cc b/lib/src/common/network_utils.cc index a2d9ed91ba..8e286413a7 100644 --- a/lib/src/common/network_utils.cc +++ b/lib/src/common/network_utils.cc @@ -112,72 +112,6 @@ int open_socket(net_utils::addr_family ip_type, net_utils::socket_type socket_ty srslog::fetch_basic_logger(LOGSERVICE).debug("Opened %s socket=%d", net_utils::protocol_to_string(protocol), fd); if (protocol == protocol_type::SCTP) { - // Sets the data_io_event to be able to use sendrecv_info - // Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown - // Also subscribes to SCTP_PEER_ADDR_CHANGE, to handle ungraceful shutdown of the link. - struct sctp_event_subscribe evnts = {}; - evnts.sctp_data_io_event = 1; - evnts.sctp_shutdown_event = 1; - evnts.sctp_address_event = 1; - if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)) != 0) { - srslog::fetch_basic_logger(LOGSERVICE).error("Failed to subscribe to SCTP_SHUTDOWN event: %s", strerror(errno)); - perror("Could not register socket to SCTP events\n"); - close(fd); - return -1; - } - - /* - * Modify SCTP default parameters for quicker detection of broken links. - * This includes changes to the SCTP_INITMSG parameters (to control the timeout of the connect() syscall) - * And changes to the maximum re-transmission timeout (rto_max), for quicker detection of broken links. - */ - // Set RTO_MAX to quickly detect broken links. - sctp_rtoinfo rto_opts; - socklen_t rto_sz = sizeof(sctp_rtoinfo); - rto_opts.srto_assoc_id = 0; - if (getsockopt(fd, SOL_SCTP, SCTP_RTOINFO, &rto_opts, &rto_sz) < 0) { - printf("Error getting RTO_INFO sockopts\n"); - close(fd); - return -1; - } - - rto_opts.srto_max = 6000; // 6 seconds - - srslog::fetch_basic_logger(LOGSERVICE) - .debug( - "Setting RTO_INFO options on SCTP socket. Association %d, Initial RTO %d, Minimum RTO %d, Maximum RTO %d", - rto_opts.srto_assoc_id, - rto_opts.srto_initial, - rto_opts.srto_min, - rto_opts.srto_max); - - if (setsockopt(fd, SOL_SCTP, SCTP_RTOINFO, &rto_opts, rto_sz) < 0) { - perror("Error setting RTO_INFO sockopts\n"); - close(fd); - return -1; - } - - // Set SCTP INITMSG options to reduce blocking timeout of connect() - sctp_initmsg init_opts; - socklen_t init_sz = sizeof(sctp_initmsg); - if (getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &init_opts, &init_sz) < 0) { - printf("Error getting sockopts\n"); - close(fd); - return -1; - } - - init_opts.sinit_max_attempts = 3; - init_opts.sinit_max_init_timeo = 5000; // 5 seconds - - srslog::fetch_basic_logger(LOGSERVICE) - .debug("Setting SCTP_INITMSG options on SCTP socket. Max attempts %d, Max init attempts timeout %d", - init_opts.sinit_max_attempts, - init_opts.sinit_max_init_timeo); - if (setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &init_opts, init_sz) < 0) { - perror("Error setting SCTP_INITMSG sockopts\n"); - close(fd); - return -1; - } } return fd; @@ -264,6 +198,104 @@ bool start_listen(int fd) return true; } +bool reuse_addr(int fd) +{ + if (fd < 0) { + srslog::fetch_basic_logger(LOGSERVICE).error("Trying reuse_addr a closed socket. Socket=%d", fd); + return false; + } + + int enable = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { + srslog::fetch_basic_logger(LOGSERVICE).error("Failed to set SO_REUSEADDR. Socket=%d", fd); + return false; + } + srslog::fetch_basic_logger(LOGSERVICE).debug("Successfully set SO_REUSEADDR. Socket=%d", fd); + return true; +} + +bool sctp_subscribe_to_events(int fd) +{ + if (fd < 0) { + srslog::fetch_basic_logger(LOGSERVICE).error("Trying subscribe to SCTP events on a closed socket. Socket=%d", fd); + return false; + } + + // Sets the data_io_event to be able to use sendrecv_info + // Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown + // Also subscribes to SCTP_PEER_ADDR_CHANGE, to handle ungraceful shutdown of the link. + struct sctp_event_subscribe evnts = {}; + evnts.sctp_data_io_event = 1; + evnts.sctp_shutdown_event = 1; + evnts.sctp_address_event = 1; + if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)) != 0) { + srslog::fetch_basic_logger(LOGSERVICE).error("Failed to subscribe to SCTP_SHUTDOWN event: %s", strerror(errno)); + perror("Could not register socket to SCTP events\n"); + close(fd); + return false; + } + return true; +} + +bool sctp_set_rto_opts(int fd) +{ + /* + * Modify SCTP default parameters for quicker detection of broken links. + * This includes changes to the SCTP_INITMSG parameters (to control the timeout of the connect() syscall) + * And changes to the maximum re-transmission timeout (rto_max), for quicker detection of broken links. + */ + // Set RTO_MAX to quickly detect broken links. + sctp_rtoinfo rto_opts; + socklen_t rto_sz = sizeof(sctp_rtoinfo); + rto_opts.srto_assoc_id = 0; + if (getsockopt(fd, SOL_SCTP, SCTP_RTOINFO, &rto_opts, &rto_sz) < 0) { + printf("Error getting RTO_INFO sockopts\n"); + close(fd); + return false; + } + + rto_opts.srto_max = 6000; // 6 seconds + + srslog::fetch_basic_logger(LOGSERVICE) + .debug("Setting RTO_INFO options on SCTP socket. Association %d, Initial RTO %d, Minimum RTO %d, Maximum RTO %d", + rto_opts.srto_assoc_id, + rto_opts.srto_initial, + rto_opts.srto_min, + rto_opts.srto_max); + + if (setsockopt(fd, SOL_SCTP, SCTP_RTOINFO, &rto_opts, rto_sz) < 0) { + perror("Error setting RTO_INFO sockopts\n"); + close(fd); + return false; + } + return true; +} + +bool sctp_set_init_msg_opts(int fd) +{ + // Set SCTP INITMSG options to reduce blocking timeout of connect() + sctp_initmsg init_opts; + socklen_t init_sz = sizeof(sctp_initmsg); + if (getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &init_opts, &init_sz) < 0) { + printf("Error getting sockopts\n"); + close(fd); + return false; + } + + init_opts.sinit_max_attempts = 3; + init_opts.sinit_max_init_timeo = 5000; // 5 seconds + + srslog::fetch_basic_logger(LOGSERVICE) + .debug("Setting SCTP_INITMSG options on SCTP socket. Max attempts %d, Max init attempts timeout %d", + init_opts.sinit_max_attempts, + init_opts.sinit_max_init_timeo); + if (setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &init_opts, init_sz) < 0) { + perror("Error setting SCTP_INITMSG sockopts\n"); + close(fd); + return false; + } + return true; +} } // namespace net_utils /******************************************** @@ -330,25 +362,25 @@ bool unique_socket::start_listen() return net_utils::start_listen(sockfd); } -/*********************************************************************** - * SCTP socket - **********************************************************************/ +bool unique_socket::reuse_addr() +{ + return net_utils::reuse_addr(sockfd); +} -namespace net_utils { +bool unique_socket::sctp_subscribe_to_events() +{ + return net_utils::sctp_subscribe_to_events(sockfd); +} -bool sctp_init_socket(unique_socket* socket, net_utils::socket_type socktype, const char* bind_addr_str, int bind_port) +bool unique_socket::sctp_set_rto_opts() { - if (not socket->open_socket(net_utils::addr_family::ipv4, socktype, net_utils::protocol_type::SCTP)) { - return false; - } - if (not socket->bind_addr(bind_addr_str, bind_port)) { - socket->close(); - return false; - } - return true; + return net_utils::sctp_set_rto_opts(sockfd); } -} // namespace net_utils +bool unique_socket::sctp_set_init_msg_opts() +{ + return net_utils::sctp_set_init_msg_opts(sockfd); +} /*************************************************************** * Rx Multisocket Handler diff --git a/lib/test/common/network_utils_test.cc b/lib/test/common/network_utils_test.cc index 31fbe2b4cf..b193b1d3fe 100644 --- a/lib/test/common/network_utils_test.cc +++ b/lib/test/common/network_utils_test.cc @@ -52,13 +52,19 @@ int test_socket_handler() const char* server_addr = "127.0.100.1"; using namespace srsran::net_utils; - TESTASSERT(sctp_init_socket(&server_socket, socket_type::seqpacket, server_addr, server_port)); + TESTASSERT(server_socket.open_socket( + srsran::net_utils::addr_family::ipv4, socket_type::seqpacket, srsran::net_utils::protocol_type::SCTP)); + TESTASSERT(server_socket.bind_addr(server_addr, server_port)); TESTASSERT(server_socket.start_listen()); logger.info("Listening from fd=%d", server_socket.fd()); - TESTASSERT(sctp_init_socket(&client_socket, socket_type::seqpacket, "127.0.0.1", 0)); - TESTASSERT(sctp_init_socket(&client_socket2, socket_type::seqpacket, "127.0.0.2", 0)); + TESTASSERT(client_socket.open_socket( + srsran::net_utils::addr_family::ipv4, socket_type::seqpacket, srsran::net_utils::protocol_type::SCTP)); + TESTASSERT(client_socket.bind_addr("127.0.0.1", 0)); TESTASSERT(client_socket.connect_to(server_addr, server_port)); + TESTASSERT(client_socket2.open_socket( + srsran::net_utils::addr_family::ipv4, socket_type::seqpacket, srsran::net_utils::protocol_type::SCTP)); + TESTASSERT(client_socket2.bind_addr("127.0.0.2", 0)); TESTASSERT(client_socket2.connect_to(server_addr, server_port)); // register server Rx handler @@ -118,12 +124,18 @@ int test_socket_handler() int test_sctp_bind_error() { srsran::unique_socket sock; - TESTASSERT(not srsran::net_utils::sctp_init_socket( - &sock, srsran::net_utils::socket_type::seqpacket, "1.1.1.1", 8000)); // Bogus IP address - // should not be able to bind - TESTASSERT(srsran::net_utils::sctp_init_socket( - &sock, srsran::net_utils::socket_type::seqpacket, "127.0.0.1", 8000)); // Good IP address - // should be able to bind + TESTASSERT(sock.open_socket(srsran::net_utils::addr_family::ipv4, + srsran::net_utils::socket_type::seqpacket, + srsran::net_utils::protocol_type::SCTP)); + TESTASSERT(sock.bind_addr("1.1.1.1", 8000)); // Bogus IP address + // should not be able to bind + + srsran::unique_socket sock2; + TESTASSERT(sock2.open_socket(srsran::net_utils::addr_family::ipv4, + srsran::net_utils::socket_type::seqpacket, + srsran::net_utils::protocol_type::SCTP)); + TESTASSERT(sock.bind_addr("127.0.0.1", 8000)); // Good IP address + // should be able to bind return SRSRAN_SUCCESS; } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 71721b4c04..4bd8ee807e 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -79,6 +79,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("enb.gtp_advertise_addr", bpo::value(&args->stack.s1ap.gtp_advertise_addr)->default_value(""), "IP address of eNB to advertise for DL GTP-U Traffic") ("enb.s1c_bind_addr", bpo::value(&args->stack.s1ap.s1c_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection") ("enb.s1c_bind_port", bpo::value(&args->stack.s1ap.s1c_bind_port)->default_value(0), "Source port for S1AP connection (0 means any)") + ("enb.s1c_reuse_addr", bpo::value(&args->stack.s1ap.s1c_reuse_addr)->default_value(false), "Use SO_REUSE_ADDR on S1-C interface.") ("enb.n_prb", bpo::value(&args->enb.n_prb)->default_value(25), "Number of PRB") ("enb.nof_ports", bpo::value(&args->enb.nof_ports)->default_value(1), "Number of ports") ("enb.tm", bpo::value(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)") diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 6fb1247283..59ab32830d 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -491,9 +491,27 @@ bool s1ap::connect_mme() using namespace srsran::net_utils; logger.info("Connecting to MME %s:%d", args.mme_addr.c_str(), int(MME_PORT)); - // Init SCTP socket and bind it - if (not srsran::net_utils::sctp_init_socket( - &mme_socket, socket_type::seqpacket, args.s1c_bind_addr.c_str(), args.s1c_bind_port)) { + // Open SCTP socket + if (not mme_socket.open_socket( + srsran::net_utils::addr_family::ipv4, socket_type::seqpacket, srsran::net_utils::protocol_type::SCTP)) { + return false; + } + + // Set SO_REUSE_ADDR if necessary + if (args.s1c_reuse_addr) { + if (not mme_socket.reuse_addr()) { + mme_socket.close(); + return false; + } + } + + mme_socket.sctp_subscribe_to_events(); + mme_socket.sctp_set_rto_opts(); + mme_socket.sctp_set_init_msg_opts(); + + // Bind socket + if (not mme_socket.bind_addr(args.s1c_bind_addr.c_str(), args.s1c_bind_port)) { + mme_socket.close(); return false; } logger.info("SCTP socket opened. fd=%d", mme_socket.fd()); diff --git a/srsgnb/src/stack/ngap/ngap.cc b/srsgnb/src/stack/ngap/ngap.cc index 16a44188b9..878b0a31f8 100644 --- a/srsgnb/src/stack/ngap/ngap.cc +++ b/srsgnb/src/stack/ngap/ngap.cc @@ -633,12 +633,23 @@ bool ngap::connect_amf() using namespace srsran::net_utils; logger.info("Connecting to AMF %s:%d", args.amf_addr.c_str(), int(AMF_PORT)); - // Init SCTP socket and bind it - if (not sctp_init_socket(&amf_socket, socket_type::seqpacket, args.ngc_bind_addr.c_str(), 0)) { + // Open SCTP socket + if (not amf_socket.open_socket( + srsran::net_utils::addr_family::ipv4, socket_type::seqpacket, srsran::net_utils::protocol_type::SCTP)) { return false; } logger.info("SCTP socket opened. fd=%d", amf_socket.fd()); + amf_socket.sctp_subscribe_to_events(); + amf_socket.sctp_set_rto_opts(); + amf_socket.sctp_set_init_msg_opts(); + + // Bind socket + if (not amf_socket.bind_addr(args.ngc_bind_addr.c_str(), 0)) { + amf_socket.close(); + return false; + } + // Connect to the AMF address if (not amf_socket.connect_to(args.amf_addr.c_str(), AMF_PORT, &amf_addr)) { return false; From 2a60562a2e389f0926633b0e6f4a1d6c99af66cb Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Mon, 11 Apr 2022 18:43:38 +0100 Subject: [PATCH 5/6] enb,s1ap: adding SCTP configuration to enb.conf --- lib/include/srsran/common/network_utils.h | 4 +-- .../srsran/interfaces/enb_s1ap_interfaces.h | 5 ++- lib/src/common/network_utils.cc | 34 +++++++++---------- lib/test/common/network_utils_test.cc | 4 +-- srsenb/src/main.cc | 6 +++- srsenb/src/stack/s1ap/s1ap.cc | 20 ++++++++--- srsgnb/src/stack/ngap/ngap.cc | 17 ++++++++-- 7 files changed, 60 insertions(+), 30 deletions(-) diff --git a/lib/include/srsran/common/network_utils.h b/lib/include/srsran/common/network_utils.h index b167d5d2e8..c9577be5ed 100644 --- a/lib/include/srsran/common/network_utils.h +++ b/lib/include/srsran/common/network_utils.h @@ -80,8 +80,8 @@ class unique_socket bool start_listen(); bool reuse_addr(); bool sctp_subscribe_to_events(); - bool sctp_set_rto_opts(); - bool sctp_set_init_msg_opts(); + bool sctp_set_rto_opts(int rto_max); + bool sctp_set_init_msg_opts(int max_init_attempts, int max_init_timeo); int get_socket() const { return sockfd; }; protected: diff --git a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h index 1ffd820267..f09486b61a 100644 --- a/lib/include/srsran/interfaces/enb_s1ap_interfaces.h +++ b/lib/include/srsran/interfaces/enb_s1ap_interfaces.h @@ -29,11 +29,14 @@ struct s1ap_args_t { std::string gtp_advertise_addr; std::string s1c_bind_addr; uint16_t s1c_bind_port; - bool s1c_reuse_addr; std::string enb_name; uint32_t ts1_reloc_prep_timeout; uint32_t ts1_reloc_overall_timeout; int32_t max_s1_setup_retries; + bool sctp_reuse_addr; + int32_t sctp_rto_max; + int32_t sctp_init_max_attempts; + int32_t sctp_max_init_timeo; }; // S1AP interface for RRC diff --git a/lib/src/common/network_utils.cc b/lib/src/common/network_utils.cc index 8e286413a7..3bf5665564 100644 --- a/lib/src/common/network_utils.cc +++ b/lib/src/common/network_utils.cc @@ -111,9 +111,6 @@ int open_socket(net_utils::addr_family ip_type, net_utils::socket_type socket_ty } srslog::fetch_basic_logger(LOGSERVICE).debug("Opened %s socket=%d", net_utils::protocol_to_string(protocol), fd); - if (protocol == protocol_type::SCTP) { - } - return fd; } @@ -237,13 +234,12 @@ bool sctp_subscribe_to_events(int fd) return true; } -bool sctp_set_rto_opts(int fd) +/* + * Modify SCTP default parameters for quicker detection of broken links. + * Changes to the maximum re-transmission timeout (rto_max). + */ +bool sctp_set_rto_opts(int fd, int rto_max) { - /* - * Modify SCTP default parameters for quicker detection of broken links. - * This includes changes to the SCTP_INITMSG parameters (to control the timeout of the connect() syscall) - * And changes to the maximum re-transmission timeout (rto_max), for quicker detection of broken links. - */ // Set RTO_MAX to quickly detect broken links. sctp_rtoinfo rto_opts; socklen_t rto_sz = sizeof(sctp_rtoinfo); @@ -254,7 +250,7 @@ bool sctp_set_rto_opts(int fd) return false; } - rto_opts.srto_max = 6000; // 6 seconds + rto_opts.srto_max = rto_max; srslog::fetch_basic_logger(LOGSERVICE) .debug("Setting RTO_INFO options on SCTP socket. Association %d, Initial RTO %d, Minimum RTO %d, Maximum RTO %d", @@ -271,7 +267,11 @@ bool sctp_set_rto_opts(int fd) return true; } -bool sctp_set_init_msg_opts(int fd) +/* + * Modify SCTP default parameters for quicker detection of broken links. + * Changes to the SCTP_INITMSG parameters (to control the timeout of the connect() syscall) + */ +bool sctp_set_init_msg_opts(int fd, int init_max_attempts, int max_init_timeo) { // Set SCTP INITMSG options to reduce blocking timeout of connect() sctp_initmsg init_opts; @@ -282,8 +282,8 @@ bool sctp_set_init_msg_opts(int fd) return false; } - init_opts.sinit_max_attempts = 3; - init_opts.sinit_max_init_timeo = 5000; // 5 seconds + init_opts.sinit_max_attempts = init_max_attempts; + init_opts.sinit_max_init_timeo = max_init_timeo; srslog::fetch_basic_logger(LOGSERVICE) .debug("Setting SCTP_INITMSG options on SCTP socket. Max attempts %d, Max init attempts timeout %d", @@ -372,14 +372,14 @@ bool unique_socket::sctp_subscribe_to_events() return net_utils::sctp_subscribe_to_events(sockfd); } -bool unique_socket::sctp_set_rto_opts() +bool unique_socket::sctp_set_rto_opts(int rto_max) { - return net_utils::sctp_set_rto_opts(sockfd); + return net_utils::sctp_set_rto_opts(sockfd, rto_max); } -bool unique_socket::sctp_set_init_msg_opts() +bool unique_socket::sctp_set_init_msg_opts(int max_init_attempts, int max_init_timeo) { - return net_utils::sctp_set_init_msg_opts(sockfd); + return net_utils::sctp_set_init_msg_opts(sockfd, max_init_attempts, max_init_timeo); } /*************************************************************** diff --git a/lib/test/common/network_utils_test.cc b/lib/test/common/network_utils_test.cc index b193b1d3fe..9711d84248 100644 --- a/lib/test/common/network_utils_test.cc +++ b/lib/test/common/network_utils_test.cc @@ -127,8 +127,8 @@ int test_sctp_bind_error() TESTASSERT(sock.open_socket(srsran::net_utils::addr_family::ipv4, srsran::net_utils::socket_type::seqpacket, srsran::net_utils::protocol_type::SCTP)); - TESTASSERT(sock.bind_addr("1.1.1.1", 8000)); // Bogus IP address - // should not be able to bind + TESTASSERT(not sock.bind_addr("1.1.1.1", 8000)); // Bogus IP address + // should not be able to bind srsran::unique_socket sock2; TESTASSERT(sock2.open_socket(srsran::net_utils::addr_family::ipv4, diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 4bd8ee807e..c367521ce6 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -79,7 +79,6 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("enb.gtp_advertise_addr", bpo::value(&args->stack.s1ap.gtp_advertise_addr)->default_value(""), "IP address of eNB to advertise for DL GTP-U Traffic") ("enb.s1c_bind_addr", bpo::value(&args->stack.s1ap.s1c_bind_addr)->default_value("192.168.3.1"), "Local IP address to bind for S1AP connection") ("enb.s1c_bind_port", bpo::value(&args->stack.s1ap.s1c_bind_port)->default_value(0), "Source port for S1AP connection (0 means any)") - ("enb.s1c_reuse_addr", bpo::value(&args->stack.s1ap.s1c_reuse_addr)->default_value(false), "Use SO_REUSE_ADDR on S1-C interface.") ("enb.n_prb", bpo::value(&args->enb.n_prb)->default_value(25), "Number of PRB") ("enb.nof_ports", bpo::value(&args->enb.nof_ports)->default_value(1), "Number of ports") ("enb.tm", bpo::value(&args->enb.transmission_mode)->default_value(1), "Transmission mode (1-8)") @@ -259,7 +258,12 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.ts1_reloc_prep_timeout", bpo::value(&args->stack.s1ap.ts1_reloc_prep_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocPrep Expiry Timeout value in milliseconds.") ("expert.ts1_reloc_overall_timeout", bpo::value(&args->stack.s1ap.ts1_reloc_overall_timeout)->default_value(10000), "S1AP TS 36.413 TS1RelocOverall Expiry Timeout value in milliseconds.") ("expert.rlf_min_ul_snr_estim", bpo::value(&args->stack.mac.rlf_min_ul_snr_estim)->default_value(-2), "SNR threshold in dB below which the eNB is notified with rlf ko.") + + ("expert.sctp_reuse_addr", bpo::value(&args->stack.s1ap.sctp_reuse_addr)->default_value(false), "Use SO_REUSE_ADDR on S1-C interface.") ("expert.max_s1_setup_retries", bpo::value(&args->stack.s1ap.max_s1_setup_retries)->default_value(-1), "Max S1 setup retries") + ("expert.sctp_rto_max", bpo::value(&args->stack.s1ap.sctp_rto_max)->default_value(6000), "SCTP maximum RTO.") + ("expert.sctp_init_max_attempts", bpo::value(&args->stack.s1ap.sctp_init_max_attempts)->default_value(3), "Maximum SCTP init attempts.") + ("expert.sctp_max_init_timeo)", bpo::value(&args->stack.s1ap.sctp_max_init_timeo)->default_value(5000), "Maximum SCTP init timeout.") ("expert.rx_gain_offset", bpo::value(&args->phy.rx_gain_offset)->default_value(62), "RX Gain offset to add to rx_gain to calibrate RSRP readings") ("expert.mac_prach_bi", bpo::value(&args->stack.mac.prach_bi)->default_value(0), "Backoff Indicator to reduce contention in the PRACH channel") diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index 59ab32830d..b78ef379ce 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -498,16 +498,28 @@ bool s1ap::connect_mme() } // Set SO_REUSE_ADDR if necessary - if (args.s1c_reuse_addr) { + if (args.sctp_reuse_addr) { if (not mme_socket.reuse_addr()) { mme_socket.close(); return false; } } - mme_socket.sctp_subscribe_to_events(); - mme_socket.sctp_set_rto_opts(); - mme_socket.sctp_set_init_msg_opts(); + // Subscribe to shutdown events + if (not mme_socket.sctp_subscribe_to_events()) { + mme_socket.close(); + return false; + } + + // Set SRTO_MAX + if (not mme_socket.sctp_set_rto_opts(args.sctp_rto_max)) { + return false; + } + + // Set SCTP init options + if (not mme_socket.sctp_set_init_msg_opts(args.sctp_init_max_attempts, args.sctp_max_init_timeo)) { + return false; + } // Bind socket if (not mme_socket.bind_addr(args.s1c_bind_addr.c_str(), args.s1c_bind_port)) { diff --git a/srsgnb/src/stack/ngap/ngap.cc b/srsgnb/src/stack/ngap/ngap.cc index 878b0a31f8..5381cea78f 100644 --- a/srsgnb/src/stack/ngap/ngap.cc +++ b/srsgnb/src/stack/ngap/ngap.cc @@ -640,9 +640,20 @@ bool ngap::connect_amf() } logger.info("SCTP socket opened. fd=%d", amf_socket.fd()); - amf_socket.sctp_subscribe_to_events(); - amf_socket.sctp_set_rto_opts(); - amf_socket.sctp_set_init_msg_opts(); + if (not amf_socket.sctp_subscribe_to_events()) { + amf_socket.close(); + return false; + } + + if (not amf_socket.sctp_set_rto_opts(5000)) { + amf_socket.close(); + return false; + } + + if (not amf_socket.sctp_set_init_msg_opts(3, 6000)) { + amf_socket.close(); + return false; + } // Bind socket if (not amf_socket.bind_addr(args.ngc_bind_addr.c_str(), 0)) { From 3c17686c0a3683ada12380c7494452cdfe3395a4 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 13 Apr 2022 11:52:56 +0100 Subject: [PATCH 6/6] enb,s1ap: make sure we trigger s1 setup failure when we get the S1 setup failure message --- srsenb/src/stack/s1ap/s1ap.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/srsenb/src/stack/s1ap/s1ap.cc b/srsenb/src/stack/s1ap/s1ap.cc index b78ef379ce..0a4e9e5470 100644 --- a/srsenb/src/stack/s1ap/s1ap.cc +++ b/srsenb/src/stack/s1ap/s1ap.cc @@ -1133,6 +1133,10 @@ bool s1ap::handle_s1setupfailure(const asn1::s1ap::s1_setup_fail_s& msg) return false; } + s1_setup_proc_t::s1setupresult res; + res.success = false; + s1setup_proc.trigger(res); + std::string cause = get_cause(msg->cause.value); logger.error("S1 Setup Failure. Cause: %s", cause.c_str()); srsran::console("S1 Setup Failure. Cause: %s\n", cause.c_str());