diff --git a/lib/include/srsran/common/network_utils.h b/lib/include/srsran/common/network_utils.h index b167d5d2e..c9577be5e 100644 --- a/lib/include/srsran/common/network_utils.h +++ b/lib/include/srsran/common/network_utils.h @@ -80,8 +80,8 @@ public: 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 1ffd82026..f09486b61 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 8e286413a..3bf566556 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 b193b1d3f..9711d8424 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 4bd8ee807..c367521ce 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 59ab32830..b78ef379c 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 878b0a31f..5381cea78 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)) {