Commit dc61ff89 authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen

First version for N2 Handover

parent 17940c21
......@@ -97,6 +97,7 @@ COPY --from=oai-amf-builder /usr/lib/x86_64-linux-gnu/libpsl.so.5 .
WORKDIR /usr/local/lib
COPY --from=oai-amf-builder /usr/lib/libboost_system.so.1.67.0 .
COPY --from=oai-amf-builder /usr/lib/libboost_thread.so.1.67.0 .
COPY --from=oai-amf-builder /usr/lib/libboost_chrono.so.1.67.0 .
COPY --from=oai-amf-builder /usr/local/lib/libpistache.so .
RUN ldconfig
......
......@@ -66,13 +66,11 @@ amf_app::amf_app(const amf_config& amf_cfg)
: m_amf_ue_ngap_id2ue_ctx(),
m_ue_ctx_key(),
m_supi2ue_ctx(),
m_curl_handle_responses(),
m_curl_handle_responses_gtp() {
amf_ue_ngap_id2ue_ctx = {};
ue_ctx_key = {};
supi2ue_ctx = {};
curl_handle_responses = {};
curl_handle_responses_gtp = {};
m_curl_handle_responses_n2_sm() {
amf_ue_ngap_id2ue_ctx = {};
ue_ctx_key = {};
supi2ue_ctx = {};
curl_handle_responses_n2_sm = {};
Logger::amf_app().startup("Creating AMF application functionality layer");
if (itti_inst->create_task(TASK_AMF_APP, amf_app_task, nullptr)) {
Logger::amf_app().error("Cannot create task TASK_AMF_APP");
......@@ -493,48 +491,21 @@ void amf_app::trigger_nf_deregistration() {
//---------------------------------------------------------------------------------------------
void amf_app::add_promise(
uint32_t id, boost::shared_ptr<boost::promise<uint32_t>>& p) {
std::unique_lock lock(m_curl_handle_responses);
curl_handle_responses.emplace(id, p);
}
//---------------------------------------------------------------------------------------------
void amf_app::remove_promise(uint32_t id) {
std::unique_lock lock(m_curl_handle_responses);
curl_handle_responses.erase(id);
}
//------------------------------------------------------------------------------
void amf_app::trigger_process_response(uint32_t pid, uint32_t http_code) {
Logger::amf_app().debug(
"Trigger process response: Set promise with ID %u "
"to ready",
pid);
std::unique_lock lock(m_curl_handle_responses);
if (curl_handle_responses.count(pid) > 0) {
curl_handle_responses[pid]->set_value(http_code);
// Remove this promise from list
curl_handle_responses.erase(pid);
}
}
//---------------------------------------------------------------------------------------------
void amf_app::add_promise(
uint32_t id, boost::shared_ptr<boost::promise<GtpTunnel_t>>& p) {
std::unique_lock lock(m_curl_handle_responses_gtp);
curl_handle_responses_gtp.emplace(id, p);
uint32_t id, boost::shared_ptr<boost::promise<std::string>>& p) {
std::unique_lock lock(m_curl_handle_responses_n2_sm);
curl_handle_responses_n2_sm.emplace(id, p);
}
//------------------------------------------------------------------------------
void amf_app::trigger_process_response(uint32_t pid, GtpTunnel_t gtp_info) {
void amf_app::trigger_process_response(uint32_t pid, std::string n2_sm) {
Logger::amf_app().debug(
"Trigger process response: Set promise with ID %u "
"to ready",
pid);
std::unique_lock lock(m_curl_handle_responses);
if (curl_handle_responses_gtp.count(pid) > 0) {
curl_handle_responses_gtp[pid]->set_value(gtp_info);
std::unique_lock lock(m_curl_handle_responses_n2_sm);
if (curl_handle_responses_n2_sm.count(pid) > 0) {
curl_handle_responses_n2_sm[pid]->set_value(n2_sm);
// Remove this promise from list
curl_handle_responses_gtp.erase(pid);
curl_handle_responses_n2_sm.erase(pid);
}
}
......@@ -162,8 +162,8 @@ class amf_app {
void trigger_process_response(uint32_t pid, uint32_t http_code);
void add_promise(
uint32_t pid, boost::shared_ptr<boost::promise<GtpTunnel_t>>& p);
void trigger_process_response(uint32_t pid, GtpTunnel_t gtp_info);
uint32_t pid, boost::shared_ptr<boost::promise<std::string>>& p);
void trigger_process_response(uint32_t pid, std::string n2_sm);
private:
// context management
......@@ -175,13 +175,9 @@ class amf_app {
std::map<std::string, std::shared_ptr<ue_context>> supi2ue_ctx;
mutable std::shared_mutex m_supi2ue_ctx;
mutable std::shared_mutex m_curl_handle_responses;
std::map<uint32_t, boost::shared_ptr<boost::promise<uint32_t>>>
curl_handle_responses;
mutable std::shared_mutex m_curl_handle_responses_gtp;
std::map<uint32_t, boost::shared_ptr<boost::promise<GtpTunnel_t>>>
curl_handle_responses_gtp;
mutable std::shared_mutex m_curl_handle_responses_n2_sm;
std::map<uint32_t, boost::shared_ptr<boost::promise<std::string>>>
curl_handle_responses_n2_sm;
};
} // namespace amf_application
......
......@@ -215,9 +215,17 @@ void amf_n11::handle_itti_message(
pdu_session_update_request["n2SmInfoType"] = itti_msg.n2sm_info_type;
pdu_session_update_request["n2SmInfo"]["contentId"] = "n2msg";
std::string json_part = pdu_session_update_request.dump();
std::string n2SmMsg;
std::string n2SmMsg = {};
octet_stream_2_hex_stream(
(uint8_t*) bdata(itti_msg.n2sm), blength(itti_msg.n2sm), n2SmMsg);
// For N2 HO
if (itti_msg.n2sm_info_type.compare("HANDOVER_REQUIRED") == 0) {
pdu_session_update_request["hoState"] = "PREPARING";
} else if (itti_msg.n2sm_info_type.compare("HANDOVER_REQ_ACK") == 0) {
pdu_session_update_request["hoState"] = "PREPARED";
}
curl_http_client(
remote_uri, json_part, "", n2SmMsg, supi, itti_msg.pdu_session_id,
itti_msg.promise_id);
......@@ -579,12 +587,6 @@ void amf_n11::curl_http_client(
Logger::amf_n11().debug("Get response with HTTP code (%d)", httpCode);
Logger::amf_n11().debug("response body %s", response.c_str());
// Notify to the result if necessary
// TODO: Notify with the N3 information
if (promise_id > 0) {
amf_app_inst->trigger_process_response(promise_id, httpCode);
}
if (static_cast<http_response_codes_e>(httpCode) ==
http_response_codes_e::HTTP_RESPONSE_CODE_0) {
// TODO: should be removed
......@@ -593,6 +595,8 @@ void amf_n11::curl_http_client(
// free curl before returning
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
return;
}
......@@ -611,9 +615,12 @@ void amf_n11::curl_http_client(
Logger::amf_n11().error("There's no content in the response");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
// TODO: send context response error
return;
}
// TODO: HO
// Transfer N1 to gNB/UE if available
if (number_parts > 1) {
......@@ -668,10 +675,28 @@ void amf_n11::curl_http_client(
"Could not get Json content from the response");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
// TODO:
return;
}
// For N2 HO
bool is_ho_procedure = false;
if (response_data.find("hoState") != response_data.end()) {
is_ho_procedure = true;
}
// Notify to the result
if ((promise_id > 0) and (is_ho_procedure)) {
amf_app_inst->trigger_process_response(
promise_id, n1sm); // actually, N2 SM Info
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_global_cleanup();
free_wrapper((void**) &body_data);
return;
}
itti_n1n2_message_transfer_request* itti_msg =
new itti_n1n2_message_transfer_request(TASK_AMF_N11, TASK_AMF_APP);
......
......@@ -1213,35 +1213,35 @@ bool amf_n2::handle_itti_message(itti_handover_required& itti_msg) {
std::vector<PDUSessionResourceSetupRequestItem_t> list;
PDUSessionResourceSetupRequestItem_t item = {};
std::map<uint32_t, boost::shared_future<uint32_t>> curl_responses;
std::map<uint8_t, boost::shared_future<std::string>> curl_responses;
for (auto pdu_session_resource : pdu_session_resource_list) {
std::shared_ptr<pdu_session_context> psc = {};
if (amf_app_inst->find_pdu_session_context(
supi, pdu_session_resource.pduSessionId, psc)) {
item.pduSessionId = psc.get()->pdu_session_id;
item.s_nssai.sst = psc.get()->snssai.sST;
item.s_nssai.sd = psc.get()->snssai.sD;
item.pduSessionNAS_PDU = nullptr;
item.pduSessionResourceSetupRequestTransfer.buf =
pdu_session_resource.HandoverRequiredTransfer.buf;
item.pduSessionResourceSetupRequestTransfer.size =
pdu_session_resource.HandoverRequiredTransfer.size;
list.push_back(item);
/* item.pduSessionId = psc.get()->pdu_session_id;
item.s_nssai.sst = psc.get()->snssai.sST;
item.s_nssai.sd = psc.get()->snssai.sD;
item.pduSessionNAS_PDU = nullptr;
item.pduSessionResourceSetupRequestTransfer.buf =
pdu_session_resource.HandoverRequiredTransfer.buf;
item.pduSessionResourceSetupRequestTransfer.size =
pdu_session_resource.HandoverRequiredTransfer.size;
list.push_back(item);
*/
// Send PDUSessionUpdateSMContextRequest to SMF for each active PDU
// sessions
// Generate a promise and associate this promise to the curl handle
uint32_t promise_id = amf_app_inst->generate_promise_id();
Logger::amf_n2().debug("Promise ID generated %d", promise_id);
boost::shared_ptr<boost::promise<uint32_t>> p =
boost::make_shared<boost::promise<uint32_t>>();
boost::shared_future<uint32_t> f = p->get_future();
boost::shared_ptr<boost::promise<std::string>> p =
boost::make_shared<boost::promise<std::string>>();
boost::shared_future<std::string> f = p->get_future();
amf_app_inst->add_promise(promise_id, p);
curl_responses.emplace(promise_id, f);
curl_responses.emplace(psc.get()->pdu_session_id, f);
Logger::amf_n2().debug(
"Sending ITTI to trigger PDUSessionUpdateSMContextRequest to SMF to "
......@@ -1269,27 +1269,6 @@ bool amf_n2::handle_itti_message(itti_handover_required& itti_msg) {
}
}
/*
for (auto pdu_session : pdu_sessions) {
if (pdu_session.get() != nullptr) {
item.pduSessionId = pdu_session.get()->pdu_session_id;
item.s_nssai.sst = pdu_session.get()->snssai.sST;
item.s_nssai.sd = pdu_session.get()->snssai.sD;
item.pduSessionNAS_PDU = NULL;
bstring n2sm = pdu_session.get()->n2sm;
if (blength(pdu_session.get()->n2sm) != 0) {
item.pduSessionResourceSetupRequestTransfer.buf =
(uint8_t*) bdata(pdu_session.get()->n2sm);
item.pduSessionResourceSetupRequestTransfer.size =
blength(pdu_session.get()->n2sm);
} else {
Logger::amf_n2().error("n2sm empty!");
}
list.push_back(item);
}
}
*/
// TODO: Handover Response supervision
// Wait until receiving all responses from SMFs before sending Handover
bool result = true;
......@@ -1303,16 +1282,33 @@ bool amf_n2::handle_itti_message(itti_handover_required& itti_msg) {
assert(curl_responses.begin()->second.has_value());
assert(!curl_responses.begin()->second.has_exception());
// Wait for the result from APP and send reply to AMF
uint32_t response_code = curl_responses.begin()->second.get();
if (static_cast<http_response_codes_e>(response_code) ==
http_response_codes_e::HTTP_RESPONSE_CODE_200_OK) {
std::string n2_sm = curl_responses.begin()->second.get();
Logger::ngap().debug(
"Got result for PDU Session ID %d", curl_responses.begin()->first);
if (n2_sm.size() > 0) {
result = result && true;
std::shared_ptr<pdu_session_context> psc = {};
if (amf_app_inst->find_pdu_session_context(
supi, curl_responses.begin()->first, psc)) {
item.pduSessionId = psc.get()->pdu_session_id;
item.s_nssai.sst = psc.get()->snssai.sST;
item.s_nssai.sd = psc.get()->snssai.sD;
item.pduSessionNAS_PDU = nullptr;
unsigned int data_len = n2_sm.length();
unsigned char* data = (unsigned char*) malloc(data_len + 1);
memset(data, 0, data_len + 1);
memcpy((void*) data, (void*) n2_sm.c_str(), data_len);
item.pduSessionResourceSetupRequestTransfer.buf = data;
item.pduSessionResourceSetupRequestTransfer.size = data_len;
list.push_back(item);
// free memory
free_wrapper((void**) &data);
}
} else {
result = false;
}
Logger::ngap().debug(
"Got result for promise ID %d", curl_responses.begin()->first);
} else {
result = true;
}
......@@ -1407,19 +1403,19 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
Logger::ngap().debug("QFI %lu", qosflowidentifiervalue);
// Send PDUSessionUpdateSMContextRequest to SMF for each active PDU sessions
std::map<uint32_t, boost::shared_future<GtpTunnel_t>> curl_responses;
std::map<uint8_t, boost::shared_future<std::string>> curl_responses;
for (auto pdu_session_resource : list) {
// Generate a promise and associate this promise to the curl handle
uint32_t promise_id = amf_app_inst->generate_promise_id();
Logger::amf_n2().debug("Promise ID generated %d", promise_id);
boost::shared_ptr<boost::promise<GtpTunnel_t>> p =
boost::make_shared<boost::promise<GtpTunnel_t>>();
boost::shared_future<GtpTunnel_t> f = p->get_future();
boost::shared_ptr<boost::promise<std::string>> p =
boost::make_shared<boost::promise<std::string>>();
boost::shared_future<std::string> f = p->get_future();
amf_app_inst->add_promise(promise_id, p);
curl_responses.emplace(promise_id, f);
curl_responses.emplace(pdu_session_resource.pduSessionId, f);
Logger::amf_n2().debug(
"Sending ITTI to trigger PDUSessionUpdateSMContextRequest to SMF to "
......@@ -1445,9 +1441,22 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
i->get_msg_name());
}
}
// send HandoverCommandMsg to Source gnb
std::unique_ptr<HandoverCommandMsg> handovercommand =
std::make_unique<HandoverCommandMsg>();
handovercommand->setMessageType();
handovercommand->setAmfUeNgapId(amf_ue_ngap_id);
handovercommand->setRanUeNgapId(unc.get()->ran_ue_ngap_id);
handovercommand->setHandoverType(Ngap_HandoverType_intra5gs);
std::shared_ptr<nas_context> nc =
amf_n1_inst->amf_ue_id_2_nas_context(amf_ue_ngap_id);
std::vector<PDUSessionResourceHandoverItem_t> handover_list;
PDUSessionResourceHandoverItem_t item = {};
// TODO: wait for response from SMF and transfer T-RAN N3 information/ or
// T-UPF to the source gNB
bool result = true;
while (!curl_responses.empty()) {
boost::future_status status;
......@@ -1459,62 +1468,66 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
assert(curl_responses.begin()->second.has_value());
assert(!curl_responses.begin()->second.has_exception());
// Wait for the result from APP and send reply to AMF
GtpTunnel_t gtp_info = curl_responses.begin()->second.get();
// TODO: process gtp_info
std::string n2_sm = curl_responses.begin()->second.get();
Logger::ngap().debug(
"Got result for promise ID %d", curl_responses.begin()->first);
"Got result for PDU Session ID %d", curl_responses.begin()->first);
if (n2_sm.size() > 0) {
result = result && true;
item.pduSessionId = curl_responses.begin()->first;
unsigned int data_len = n2_sm.length();
unsigned char* data = (unsigned char*) malloc(data_len + 1);
memset(data, 0, data_len + 1);
memcpy((void*) data, (void*) n2_sm.c_str(), data_len);
item.HandoverCommandTransfer.buf = data;
item.HandoverCommandTransfer.size = data_len;
handover_list.push_back(item);
// free memory
free_wrapper((void**) &data);
} else {
result = false;
}
} else {
result = true;
}
curl_responses.erase(curl_responses.begin());
}
// TODO: process result
// send HandoverCommandMsg to Source gnb
std::unique_ptr<HandoverCommandMsg> handovercommand =
std::make_unique<HandoverCommandMsg>();
handovercommand->setMessageType();
handovercommand->setAmfUeNgapId(amf_ue_ngap_id);
handovercommand->setRanUeNgapId(unc.get()->ran_ue_ngap_id);
handovercommand->setHandoverType(Ngap_HandoverType_intra5gs);
std::shared_ptr<nas_context> nc =
amf_n1_inst->amf_ue_id_2_nas_context(amf_ue_ngap_id);
std::vector<PDUSessionResourceHandoverItem_t> handover_list;
PDUSessionResourceHandoverItem_t item = {};
item.pduSessionId = list[0].pduSessionId;
// qosFLowtobeforwardedlist
std::vector<QosFlowToBeForwardedItem_t> forward_list;
QosFlowToBeForwardedItem_t forward_item;
forward_item.QFI = qosflowidentifiervalue;
forward_list.push_back(forward_item);
// set dlforwardingup_tnlinformation
// TransportLayerAddress *transportlayeraddress = new TransportLayerAddress();
// transportlayeraddress->setTransportLayerAddress(n3_ip_address);
// GtpTeid *gtpTeid = new GtpTeid();
// gtpTeid->setGtpTeid(teid);
PDUSessionResourceHandoverCommandTransfer* handovercommandtransfer =
new PDUSessionResourceHandoverCommandTransfer();
handovercommandtransfer->setQosFlowToBeForwardedList(forward_list);
GtpTunnel_t uptlinfo = {};
uptlinfo.gtp_teid = teid;
uptlinfo.ip_address = n3_ip_address;
handovercommandtransfer->setUPTransportLayerInformation(uptlinfo);
uint8_t buffer_ho_cmd_transfer[BUFFER_SIZE_512];
int encoded_size =
handovercommandtransfer->encodePDUSessionResourceHandoverCommandTransfer(
buffer_ho_cmd_transfer, BUFFER_SIZE_512);
item.HandoverCommandTransfer.buf = buffer_ho_cmd_transfer;
item.HandoverCommandTransfer.size = encoded_size;
handover_list.push_back(item);
/*
item.pduSessionId = list[0].pduSessionId;
// qosFLowtobeforwardedlist
std::vector<QosFlowToBeForwardedItem_t> forward_list;
QosFlowToBeForwardedItem_t forward_item;
forward_item.QFI = qosflowidentifiervalue;
forward_list.push_back(forward_item);
// set dlforwardingup_tnlinformation
// TransportLayerAddress *transportlayeraddress = new
TransportLayerAddress();
// transportlayeraddress->setTransportLayerAddress(n3_ip_address);
// GtpTeid *gtpTeid = new GtpTeid();
// gtpTeid->setGtpTeid(teid);
PDUSessionResourceHandoverCommandTransfer* handovercommandtransfer =
new PDUSessionResourceHandoverCommandTransfer();
handovercommandtransfer->setQosFlowToBeForwardedList(forward_list);
GtpTunnel_t uptlinfo = {};
uptlinfo.gtp_teid = teid;
uptlinfo.ip_address = n3_ip_address;
handovercommandtransfer->setUPTransportLayerInformation(uptlinfo);
uint8_t buffer_ho_cmd_transfer[BUFFER_SIZE_512];
int encoded_size =
handovercommandtransfer->encodePDUSessionResourceHandoverCommandTransfer(
buffer_ho_cmd_transfer, BUFFER_SIZE_512);
item.HandoverCommandTransfer.buf = buffer_ho_cmd_transfer;
item.HandoverCommandTransfer.size = encoded_size;
handover_list.push_back(item);
*/
handovercommand->setPduSessionResourceHandoverList(handover_list);
handovercommand->setTargetToSource_TransparentContainer(targetTosource);
uint8_t buffer[BUFFER_SIZE_1024];
encoded_size = handovercommand->encode2buffer(buffer, BUFFER_SIZE_1024);
bstring b = blk2bstr(buffer, encoded_size);
int encoded_size = handovercommand->encode2buffer(buffer, BUFFER_SIZE_1024);
bstring b = blk2bstr(buffer, encoded_size);
sctp_s_38412.sctp_send_msg(unc.get()->gnb_assoc_id, 0, &b);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment