// vi: ts=4 sw=4 noet: /* ================================================================================== Copyright (c) 2020 Nokia Copyright (c) 2020 AT&T Intellectual Property. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================================================== */ /* Mnemonic: ts_xapp.cpp Abstract: Traffic Steering xApp; 1. Receives A1 Policy 2. Queries SDL to decide which UE to attempt Traffic Steering for 3. Requests prediction for UE throughput on current and neighbor cells 4. Receives prediction 5. Optionally exercises Traffic Steering action over E2 Date: 22 April 2020 Author: Ron Shacham */ #include #include #include #include #include #include #include #include #include #include #include "ricxfcpp/xapp.hpp" using Namespace = std::string; using Key = std::string; using Data = std::vector; using DataMap = std::map; using Keys = std::set; // ---------------------------------------------------------- std::unique_ptr xfw; void policy_callback( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) { long now; long total_count; int sz; int i; int response_to = 0; // max timeout wating for a response int send_mtype = 0; int rmtype; // received message type int delay = 1000000; // mu-sec delay; default 1s std::unique_ptr msg; Msg_component send_payload; // special type of unique pointer to the payload fprintf( stderr, "Policy Callback got a message, type=%d , length=%d\n" , mtype, len); fprintf(stderr, "payload is %s\n", payload.get()); //fprintf( stderr, "callback 1 got a message type = %d len = %d\n", mtype, len ); mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK1\n" ); // validate that we can use the same buffer for 2 rts calls mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\n" ); mtype = 0; fprintf(stderr, "cb 1\n"); msg = xfw->Alloc_msg( 2048 ); sz = msg->Get_available_size(); // we'll reuse a message if we received one back; ensure it's big enough if( sz < 2048 ) { fprintf( stderr, " fail: message returned did not have enough size: %d [%d]\n", sz, i ); exit( 1 ); } fprintf(stderr, "cb 2"); send_payload = msg->Get_payload(); // direct access to payload snprintf( (char *) send_payload.get(), 2048, "{\"UEPredictionSet\" : [\"222\", \"333\", \"444\"]}" ); fprintf(stderr, "cb 3"); // payload updated in place, nothing to copy from, so payload parm is nil if ( ! msg->Send_msg( mtype, Message::NO_SUBID, strlen( (char *) send_payload.get() )+1, NULL )) { fprintf( stderr, " send failed: %d\n", msg->Get_state() ); } fprintf(stderr, "cb 4"); /* msg = xfw->Receive( response_to ); if( msg != NULL ) { rmtype = msg->Get_mtype(); send_payload = msg->Get_payload(); fprintf( stderr, "got: mtype=%d payload=(%s)\n", rmtype, (char *) send_payload.get() ); } */ } void prediction_callback( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) { long now; long total_count; int sz; int i; int response_to = 0; // max timeout wating for a response int send_mtype = 0; int rmtype; // received message type int delay = 1000000; // mu-sec delay; default 1s std::unique_ptr msg; Msg_component send_payload; // special type of unique pointer to the payload fprintf( stderr, "Prediction Callback got a message, type=%d , length=%d\n" , mtype, len); fprintf(stderr, "payload is %s\n", payload.get()); mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK1\n" ); // validate that we can use the same buffer for 2 rts calls mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\n" ); mtype = 0; fprintf(stderr, "cb 1\n"); } extern int main( int argc, char** argv ) { std::unique_ptr msg; Msg_component payload; // special type of unique pointer to the payload int nthreads = 1; int response_to = 0; // max timeout wating for a response int delay = 1000000; // mu-sec delay; default 1s char* port = (char *) "4560"; int ai; ai = 1; while( ai < argc ) { // very simple flag processing (no bounds/error checking) if( argv[ai][0] != '-' ) { break; } switch( argv[ai][1] ) { // we only support -x so -xy must be -x -y case 'd': // delay between messages (mu-sec) delay = atoi( argv[ai+1] ); ai++; break; case 'p': port = argv[ai+1]; ai++; break; case 't': // timeout in seconds; we need to convert to ms for rmr calls response_to = atoi( argv[ai+1] ) * 1000; ai++; break; } ai++; } fprintf( stderr, " response timeout set to: %d\n", response_to ); fprintf( stderr, " listening on port: %s\n", port ); xfw = std::unique_ptr( new Xapp( port, true ) ); // new xAPP thing; wait for a route table fprintf(stderr, "code1\n"); xfw->Add_msg_cb( 20010, policy_callback, NULL ); xfw->Add_msg_cb( 30002, prediction_callback, NULL ); fprintf(stderr, "code2\n"); std::string sdl_namespace_u = "TS-UE-metrics"; std::string sdl_namespace_c = "TS-cell-metrics"; fprintf(stderr, "code5\n"); std::unique_ptr sdl(shareddatalayer::SyncStorage::create()); Namespace nsu(sdl_namespace_u); Namespace nsc(sdl_namespace_c); /* fprintf(stderr, "before sdl set\n"); try{ //connecting to the Redis and generating a random key for namespace "hwxapp" fprintf(stderr, "IN SDL Set Data"); // std::string data_string = "{\"rsrp\" : -110}"; std::string data_string = "{\"CellID\": \"310-680-200-555001\", \"MeasTimestampPDCPBytes\": \"2020-03-18 02:23:18.220\", \"MeasPeriodPDCPBytes\": 20, \"PDCPBytesDL\": 2000000, \"PDCPBytesUL\": 1200000, \"MeasTimestampAvailPRB\": \"2020-03-18 02:23:18.220\", \"MeasPeriodAvailPRB\": 20, \"AvailPRBDL\": 30, \"AvailPRBUL\": 50 }"; DataMap dmap; // char key[4]="abc"; char key[] = "310-680-200-555001"; std::cout << "KEY: "<< key << std::endl; Key k = key; Data d; // uint8_t num = 101; d.assign(data_string.begin(), data_string.end()); // d.push_back(num); dmap.insert({k,d}); sdl->set(nsc, dmap); data_string = "{ \"CellID\": \"310-680-200-555002\", \"MeasTimestampPDCPBytes\": \"2020-03-18 02:23:18.220\", \"MeasPeriodPDCPBytes\": 20, \"PDCPBytesDL\": 800000, \"PDCPBytesUL\": 400000, \"MeasTimestampAvailPRB\": \"2020-03-18 02:23:18.220\", \"MeasPeriodAvailPRB\": 20, \"AvailPRBDL\": 30, \"AvailPRBUL\": 45 }"; Data d2; DataMap dmap2; char key2[] = "310-680-200-555002"; std::cout << "KEY: "<< key2 << std::endl; Key k2 = key2; d2.assign(data_string.begin(), data_string.end()); // d.push_back(num); dmap2.insert({k2,d}); sdl->set(nsc, dmap2); std::string data_string = "{ \"CellID\": \"310-680-200-555003\", \"MeasTimestampPDCPBytes\": \"2020-03-18 02:23:18.220\", \"MeasPeriodPDCPBytes\": 20, \"PDCPBytesDL\": 800000, \"PDCPBytesUL\": 400000, \"MeasTimestampAvailPRB\": \"2020-03-18 02:23:18.220\", \"MeasPeriodAvailPRB\": 20, \"AvailPRBDL\": 30, \"AvailPRBUL\": 45 }"; Data d3; DataMap dmap3; char key3[] = "310-680-200-555003"; std::cout << "KEY: "<< key3 << std::endl; Key k3 = key3; d3.assign(data_string.begin(), data_string.end()); // d.push_back(num); dmap3.insert({k3,d3}); sdl->set(nsc, dmap3); data_string = "{ \"UEID\": 12345, \"ServingCellID\": \"310-680-200-555002\", \"MeasTimestampUEPDCPBytes\": \"2020-03-18 02:23:18.220\", \"MeasPeriodUEPDCPBytes\": 20,\"UEPDCPBytesDL\": 250000,\"UEPDCPBytesUL\": 100000, \"MeasTimestampUEPRBUsage\": \"2020-03-18 02:23:18.220\", \"MeasPeriodUEPRBUsage\": 20, \"UEPRBUsageDL\": 10, \"UEPRBUsageUL\": 30, \"MeasTimestampRF\": \"2020-03-18 02:23:18.210\",\"MeasPeriodRF\": 40, \"ServingCellRF\": [-115,-16,-5], \"NeighborCellRF\": [ {\"CID\": \"310-680-200-555001\",\"Cell-RF\": [-90,-13,-2.5 ] }, {\"CID\": \"310-680-200-555003\", \"Cell-RF\": [-140,-17,-6 ] } ] }"; Data d4; DataMap dmap4; char key4[] = "12345"; std::cout << "KEY: "<< key << std::endl; d4.assign(data_string.begin(), data_string.end()); Key k4 = key4; // d.push_back(num); dmap4.insert({k4,d4}); sdl->set(nsu, dmap4); } catch(...){ fprintf(stderr,"SDL Error in Set Data for Namespace"); return false; } fprintf(stderr, "after sdl set\n"); */ fprintf(stderr, "before sdl get\n"); std::string prefix2="310"; Keys K = sdl->findKeys(nsc, prefix2); // just the prefix DataMap Dk = sdl->get(nsc, K); std::cout << "K contains " << K.size() << " elements.\n"; fprintf(stderr, "before forloop\n"); for(auto si=K.begin();si!=K.end();++si){ std::vector val_v = Dk[(*si)]; // 4 lines to unpack a string char val[val_v.size()+1]; // from Data int i; for(i=0;ifindKeys(nsu, prefix3); // just the prefix DataMap Dk2 = sdl->get(nsu, K2); std::cout << "K contains " << K2.size() << " elements.\n"; fprintf(stderr, "before forloop\n"); for(auto si=K2.begin();si!=K2.end();++si){ std::vector val_v = Dk2[(*si)]; // 4 lines to unpack a string char val[val_v.size()+1]; // from Data int i; for(i=0;iRun( nthreads ); fprintf(stderr, "code3\n"); msg = xfw->Alloc_msg( 2048 ); fprintf(stderr, "code4\n"); }