2 ==================================================================================
4 Copyright (c) 2018-2019 AT&T Intellectual Property.
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
21 #include "NetworkProtector.h"
24 #include <mutex> // std::mutex
25 #include <ctime> // For time()
26 #include <cstdlib> // For srand() and rand()
29 protector::protector( bool report){
30 m_access = std::make_unique<std::mutex>();
31 report_mode_only = report;
33 // there is always a default policy with id 0 (never gets deleted, can only be re-configured)
34 // default values from policy constructor will be used.
35 policy_list.insert(std::pair<int, protector_policy>(0, protector_policy()));
39 // constructor that over-rides default values for policy 0
40 protector::protector( bool enforce, int window_size, int threshold, double blocking_rate, bool report){
41 m_access = std::make_unique<std::mutex>();
42 report_mode_only = report;
44 // there is always a default policy with id 0 (never gets deleted, can only be re-configured)
45 policy_list.insert(std::pair<int, protector_policy>(0, protector_policy(enforce, window_size, threshold, blocking_rate)));
50 bool protector::operator()(unsigned char *msg_ref, size_t msg_size, unsigned char * buffer, size_t *buf_size ){
53 protector_policy * policy_ref;
55 std::lock_guard<std::mutex> lck(*(m_access.get()));
57 X2N_X2AP_PDU_t * x2ap_recv = 0;
58 asn_dec_rval_t dec_res;
61 dec_res = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_X2N_X2AP_PDU, (void **)&x2ap_recv, msg_ref, msg_size);
63 if (dec_res.code == RC_OK){
64 /* Is this an SgNB Addition request ? */
65 mdclog_write(MDCLOG_DEBUG, "Decoded X2AP PDU successfully. Processing X2 message fields to ascertain type etc ...\n");
66 if (x2ap_recv->present == X2N_X2AP_PDU_PR_initiatingMessage){
67 if (x2ap_recv->choice.initiatingMessage->procedureCode == X2N_ProcedureCode_id_sgNBAdditionPreparation ){
68 if (x2ap_recv->choice.initiatingMessage->value.present == X2N_InitiatingMessage__value_PR_SgNBAdditionRequest){
69 mdclog_write(MDCLOG_DEBUG, "Processing X2AP SgNB Addition Request message\n");
73 mdclog_write(MDCLOG_ERR, "Error :: %s, %d:: X2AP Message (%d) not an SgNB Addition Request\n", __FILE__, __LINE__, x2ap_recv->choice.initiatingMessage->value.present);
78 mdclog_write(MDCLOG_ERR, "Error :: %s, %d:: X2AP procedure code %ld does not match required %ld\n", __FILE__, __LINE__, x2ap_recv->choice.initiatingMessage->procedureCode, X2N_ProcedureCode_id_sgNBAdditionPreparation);
83 mdclog_write(MDCLOG_ERR, "Error :: %s, %d:: Not an X2AP initiating message. X2AP Message type %d\n", __FILE__, __LINE__, x2ap_recv->present);
88 mdclog_write(MDCLOG_ERR, "Error :: %s, %d :: Could not decode X2AP PDU of size %lu bytes\n", __FILE__, __LINE__, msg_size);
94 mdclog_write(MDCLOG_DEBUG, "Extracting SgNB Addition Request fields...");
96 //std::cout <<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl;
97 //xer_fprint(stdout, &asn_DEF_X2AP_PDU, x2ap_recv);
98 //std::cout <<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl;
100 res = sgnb_req.get_fields(x2ap_recv->choice.initiatingMessage, sgnb_data);
102 mdclog_write(MDCLOG_ERR, "Error :: %s, %d :: could not get fields from SgNB Addition Request. Reason = %s\n", __FILE__, __LINE__, sgnb_req.get_error().c_str());
106 mdclog_write(MDCLOG_DEBUG, "Decoded and extracted X2AP PDU data. Number of erabs = %lu\n", sgnb_data.get_list()->size());
107 mdclog_write(MDCLOG_DEBUG, "Applying admission control logic ...");
109 // Find if policy associated with this subscription id
110 auto it_policy = policy_list.find(sgnb_data.subscriber_profile_id);
112 if (it_policy == policy_list.end()){
113 // apply default policy
114 policy_ref = & policy_list[0];
117 policy_ref = & (it_policy->second);
122 policy_ref->_window_ref.get()->update_window(1);
124 // apply blocking probability if m_enforce
125 if ( policy_ref->_enforce && policy_ref->_window_ref.get()->net_events > policy_ref->_threshold){
126 res = selectiveBlock(policy_ref->_block_rate);
137 mdclog_write(MDCLOG_DEBUG, "Plugin decision for sgnb request = %d\n", res);
140 Generate response message if flag is set
143 if(! report_mode_only){
144 // generate sgnb addition response message (ack or reject)
145 // if rejecting , we use cause = Misc and sub-cause = om_intervention
146 mdclog_write(MDCLOG_DEBUG, "Generating X2AP response ..\n");
147 sgnb_data.cause = X2N_Cause_PR_misc;
148 sgnb_data.cause_desc = X2N_CauseMisc_om_intervention;
150 res = sgnb_resp.encode_sgnb_addition_response(buffer, buf_size, sgnb_data, res);
152 mdclog_write(MDCLOG_ERR, "Error :: %s, %d :: could not encode SgNB Addition Response PDU. Reason = %s\n", __FILE__, __LINE__, sgnb_resp.get_error().c_str());
155 catch(std::exception &e){
156 mdclog_write(MDCLOG_ERR, "Error:: %s, %d : Caught exception %s\n", __FILE__, __LINE__, e.what());
167 ASN_STRUCT_FREE(asn_DEF_X2N_X2AP_PDU, x2ap_recv);
172 // configure an existing policy
173 bool protector::configure(bool enforce, int windowSize_, int threshold_, double blockRate_, int id){
174 std::lock_guard<std::mutex> lck(*(m_access.get()));
175 std::stringstream ss;
177 // basic validation of input
178 if(windowSize_ <= 0){
179 ss << "Illegal value for window size = " << windowSize_ << " when configuring policy " << std::endl;
180 error_string = ss.str();
185 ss << "Illegal value for trigger threshold = " << threshold_ << " when configuring policy " << std::endl;
186 error_string = ss.str();
190 if(blockRate_ < 0 || blockRate_ > 100){
191 ss << "Illegal value for blocking rate = " << blockRate_ << " when configuring policy " << std::endl;
192 error_string = ss.str();
196 ss << "Illegal value for class id = " << id << " when configuring policy " << std::endl;
197 error_string = ss.str();
202 auto policy_it = policy_list.find(id);
203 if (policy_it == policy_list.end()){
204 mdclog_write(MDCLOG_ERR, "Error : %s, %d : No policy with id %d found for configuration\n", __FILE__, __LINE__, id);
208 bool res = policy_it->second._window_ref.get()->resize_window(windowSize_);
210 error_string = policy_it->second._window_ref.get()->get_error();
213 policy_it->second._window_size = windowSize_;
215 // enforce is set globally
216 policy_it->second._enforce = enforce;
218 policy_it->second._threshold=threshold_;
219 policy_it->second._block_rate=blockRate_;
220 mdclog_write(MDCLOG_DEBUG, "Configured policy with id %d with enforce=%d, window size = %d, threshold = %d, blocking rate = %f\n", id, policy_it->second._enforce, policy_it->second._window_size, policy_it->second._threshold, policy_it->second._block_rate);
226 bool protector::add_policy(bool enforce, int windowSize_, int threshold_, double blockRate_, int id){
227 std::lock_guard<std::mutex> lck(*(m_access.get()));
228 std::stringstream ss;
232 auto policy_it = policy_list.find(id);
233 if (policy_it != policy_list.end()){
234 ss <<"Error : " << __FILE__ << "," << __LINE__ << ": " << "Policy with id " << id << " already exists. Cannot be added" << std::endl;
235 error_string = ss.str();
236 mdclog_write(MDCLOG_ERR, "%s\n", error_string.c_str());
240 // basic validation of input
241 if(windowSize_ <= 0){
242 ss << "Illegal value for window size = " << windowSize_ << " when adding policy " << std::endl;
243 error_string = ss.str();
247 ss << "Illegal value for trigger threshold = " << threshold_ << " when adding policy " << std::endl;
248 error_string = ss.str();
252 if(blockRate_ < 0 || blockRate_ > 100){
253 ss << "Illegal value for blocking rate = " << blockRate_ << " when adding policy " << std::endl;
254 error_string = ss.str();
258 ss << "Illegal value for class id = " << id << " when adding policy " << std::endl;
259 error_string = ss.str();
266 policy_list.insert(std::pair<int, protector_policy> (id, protector_policy(enforce, windowSize_, threshold_, blockRate_)));
268 catch(std::exception &e){
269 ss <<"Error : " << __FILE__ << "," << __LINE__ << ": " << "Error creating policy. Reason = " << e.what() << std::endl;
270 error_string = ss.str();
271 mdclog_write(MDCLOG_ERR, "%s\n", error_string.c_str());
275 mdclog_write(MDCLOG_DEBUG, "Added new policy with id %d with enforce=%d, window size = %d, threshold = %d, blocking rate = %f\n", id, enforce, windowSize_, threshold_, blockRate_);
281 bool protector::delete_policy(int id){
282 std::lock_guard<std::mutex> lck(*(m_access.get()));
283 std::stringstream ss;
284 auto policy_it = policy_list.find(id);
285 if (policy_it == policy_list.end()){
286 ss <<"Error : " << __FILE__ << "," << __LINE__ << ": " << " No policy with id = " << id << " found" << std::endl;
287 error_string = ss.str();
288 mdclog_write(MDCLOG_ERR, "%s\n", error_string.c_str());
292 policy_list.erase(policy_it);
293 mdclog_write(MDCLOG_DEBUG, "Deleted policy %d\n", id);
298 // query a policy : responsibility of caller to ensure
300 // returns parameters of policy in the vector
301 bool protector::query_policy(int id, std::vector<double> & info){
303 std::lock_guard<std::mutex> lck(*(m_access.get()));
304 auto policy_it = policy_list.find(id);
305 if (policy_it == policy_list.end()){
309 info.push_back(policy_it->second._enforce);
310 info.push_back(policy_it->second._window_size);
311 info.push_back(policy_it->second._threshold);
312 info.push_back(policy_it->second._block_rate);
316 // returns requests that fall under a policy
317 // if id is -1, returns total requests
318 // if non-existent policy, returns -1
319 // counters are cumulative
320 long int protector::get_requests(int id) const {
325 std::lock_guard<std::mutex> lck(*(m_access.get()));
326 auto policy_it = policy_list.find(id);
327 if (policy_it == policy_list.end()){
331 return policy_it->second._req;
336 // returns requests that fall under a policy
337 // if id is -1 , returns total rejects
338 // if non-existent policy, returns -1
339 // counters are cumulative
340 long int protector::get_rejects(int id) const {
346 std::lock_guard<std::mutex> lck(*(m_access.get()));
347 auto policy_it = policy_list.find(id);
348 if (policy_it == policy_list.end()){
352 return policy_it->second._rej;
357 // returns list of active policies in
358 // supplied vector (policy is indexed by subscriber profile id)
359 void protector::get_active_policies(std::vector<int> & active){
360 std::lock_guard<std::mutex> lck(*(m_access.get()));
361 for (const auto &e : policy_list){
362 active.push_back(e.first);
366 // returns true if policy active else false
367 bool protector::is_active(int id){
368 auto policy_it = policy_list.find(id);
369 if (policy_it == policy_list.end()){
377 // clears counters for all policies
378 void protector::clear()
381 std::lock_guard<std::mutex> lck(*(m_access.get()));
383 for(auto &e : policy_list){
384 e.second._window_ref.get()->clear();
385 e.second._counter = 0;
395 bool protector::selectiveBlock(double block_rate)
397 unsigned int num = (rand() % 100) + 1;
398 if (num > block_rate) //not blocking