3 ==================================================================================
4 Copyright (c) 2020 Nokia
5 Copyright (c) 2020 AT&T Intellectual Property.
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 ==================================================================================
23 Abstract: Traffic Steering xApp;
25 2. Queries SDL to decide which UE to attempt Traffic Steering for
26 3. Requests prediction for UE throughput on current and neighbor cells
27 4. Receives prediction
28 5. Optionally exercises Traffic Steering action over E2
42 #include <sdl/syncstorage.hpp>
48 #include "ricxfcpp/xapp.hpp"
50 using Namespace = std::string;
51 using Key = std::string;
52 using Data = std::vector<uint8_t>;
53 using DataMap = std::map<Key, Data>;
54 using Keys = std::set<Key>;
57 // ----------------------------------------------------------
59 std::unique_ptr<Xapp> xfw;
62 void policy_callback( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) {
70 int response_to = 0; // max timeout wating for a response
73 int rmtype; // received message type
74 int delay = 1000000; // mu-sec delay; default 1s
76 std::unique_ptr<Message> msg;
77 Msg_component send_payload; // special type of unique pointer to the payload
79 fprintf( stderr, "Policy Callback got a message, type=%d , length=%d\n" , mtype, len);
80 fprintf(stderr, "payload is %s\n", payload.get());
82 //fprintf( stderr, "callback 1 got a message type = %d len = %d\n", mtype, len );
83 mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK1\n" ); // validate that we can use the same buffer for 2 rts calls
84 mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\n" );
88 fprintf(stderr, "cb 1\n");
90 msg = xfw->Alloc_msg( 2048 );
92 sz = msg->Get_available_size(); // we'll reuse a message if we received one back; ensure it's big enough
94 fprintf( stderr, "<SNDR> fail: message returned did not have enough size: %d [%d]\n", sz, i );
98 fprintf(stderr, "cb 2");
100 send_payload = msg->Get_payload(); // direct access to payload
101 snprintf( (char *) send_payload.get(), 2048, "{\"UEPredictionSet\" : [\"222\", \"333\", \"444\"]}" );
103 fprintf(stderr, "cb 3");
105 // payload updated in place, nothing to copy from, so payload parm is nil
106 if ( ! msg->Send_msg( mtype, Message::NO_SUBID, strlen( (char *) send_payload.get() )+1, NULL )) {
107 fprintf( stderr, "<SNDR> send failed: %d\n", msg->Get_state() );
110 fprintf(stderr, "cb 4");
113 msg = xfw->Receive( response_to );
115 rmtype = msg->Get_mtype();
116 send_payload = msg->Get_payload();
117 fprintf( stderr, "got: mtype=%d payload=(%s)\n", rmtype, (char *) send_payload.get() );
124 void prediction_callback( Message& mbuf, int mtype, int subid, int len, Msg_component payload, void* data ) {
132 int response_to = 0; // max timeout wating for a response
135 int rmtype; // received message type
136 int delay = 1000000; // mu-sec delay; default 1s
138 std::unique_ptr<Message> msg;
139 Msg_component send_payload; // special type of unique pointer to the payload
141 fprintf( stderr, "Prediction Callback got a message, type=%d , length=%d\n" , mtype, len);
142 fprintf(stderr, "payload is %s\n", payload.get());
144 mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK1\n" ); // validate that we can use the same buffer for 2 rts calls
145 mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\n" );
149 fprintf(stderr, "cb 1\n");
155 extern int main( int argc, char** argv ) {
157 std::unique_ptr<Message> msg;
158 Msg_component payload; // special type of unique pointer to the payload
162 int response_to = 0; // max timeout wating for a response
164 int delay = 1000000; // mu-sec delay; default 1s
166 char* port = (char *) "4560";
171 while( ai < argc ) { // very simple flag processing (no bounds/error checking)
172 if( argv[ai][0] != '-' ) {
176 switch( argv[ai][1] ) { // we only support -x so -xy must be -x -y
177 case 'd': // delay between messages (mu-sec)
178 delay = atoi( argv[ai+1] );
187 case 't': // timeout in seconds; we need to convert to ms for rmr calls
188 response_to = atoi( argv[ai+1] ) * 1000;
195 fprintf( stderr, "<XAPP> response timeout set to: %d\n", response_to );
196 fprintf( stderr, "<XAPP> listening on port: %s\n", port );
198 xfw = std::unique_ptr<Xapp>( new Xapp( port, true ) ); // new xAPP thing; wait for a route table
200 fprintf(stderr, "code1\n");
202 xfw->Add_msg_cb( 20010, policy_callback, NULL );
203 xfw->Add_msg_cb( 30002, prediction_callback, NULL );
205 fprintf(stderr, "code2\n");
207 std::string sdl_namespace_u = "TS-UE-metrics";
208 std::string sdl_namespace_c = "TS-cell-metrics";
210 fprintf(stderr, "code5\n");
212 std::unique_ptr<shareddatalayer::SyncStorage> sdl(shareddatalayer::SyncStorage::create());
214 Namespace nsu(sdl_namespace_u);
215 Namespace nsc(sdl_namespace_c);
219 fprintf(stderr, "before sdl set\n");
222 //connecting to the Redis and generating a random key for namespace "hwxapp"
223 fprintf(stderr, "IN SDL Set Data");
224 // std::string data_string = "{\"rsrp\" : -110}";
227 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 }";
230 // char key[4]="abc";
231 char key[] = "310-680-200-555001";
232 std::cout << "KEY: "<< key << std::endl;
235 // uint8_t num = 101;
236 d.assign(data_string.begin(), data_string.end());
242 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 }";
246 char key2[] = "310-680-200-555002";
247 std::cout << "KEY: "<< key2 << std::endl;
249 d2.assign(data_string.begin(), data_string.end());
251 dmap2.insert({k2,d});
253 sdl->set(nsc, dmap2);
257 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 }";
261 char key3[] = "310-680-200-555003";
262 std::cout << "KEY: "<< key3 << std::endl;
264 d3.assign(data_string.begin(), data_string.end());
266 dmap3.insert({k3,d3});
268 sdl->set(nsc, dmap3);
272 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 ] } ] }";
276 char key4[] = "12345";
277 std::cout << "KEY: "<< key << std::endl;
278 d4.assign(data_string.begin(), data_string.end());
281 dmap4.insert({k4,d4});
283 sdl->set(nsu, dmap4);
288 fprintf(stderr,"SDL Error in Set Data for Namespace");
292 fprintf(stderr, "after sdl set\n");
296 fprintf(stderr, "before sdl get\n");
299 std::string prefix2="310";
300 Keys K = sdl->findKeys(nsc, prefix2); // just the prefix
301 DataMap Dk = sdl->get(nsc, K);
303 std::cout << "K contains " << K.size() << " elements.\n";
305 fprintf(stderr, "before forloop\n");
307 for(auto si=K.begin();si!=K.end();++si){
308 std::vector<uint8_t> val_v = Dk[(*si)]; // 4 lines to unpack a string
309 char val[val_v.size()+1]; // from Data
311 for(i=0;i<val_v.size();++i) val[i] = (char)(val_v[i]);
313 fprintf(stderr, "KEYS and Values %s = %s\n",(*si).c_str(), val);
317 std::string prefix3="12";
318 Keys K2 = sdl->findKeys(nsu, prefix3); // just the prefix
319 DataMap Dk2 = sdl->get(nsu, K2);
321 std::cout << "K contains " << K2.size() << " elements.\n";
323 fprintf(stderr, "before forloop\n");
325 for(auto si=K2.begin();si!=K2.end();++si){
326 std::vector<uint8_t> val_v = Dk2[(*si)]; // 4 lines to unpack a string
327 char val[val_v.size()+1]; // from Data
329 for(i=0;i<val_v.size();++i) val[i] = (char)(val_v[i]);
331 fprintf(stderr, "KEYS and Values %s = %s\n",(*si).c_str(), val);
335 fprintf(stderr, "after sdl get\n");
337 xfw->Run( nthreads );
339 fprintf(stderr, "code3\n");
341 msg = xfw->Alloc_msg( 2048 );
343 fprintf(stderr, "code4\n");