blob: 9a59487248f9ebb142dc5ef5353ed0053cc82c1e [file] [log] [blame]
Girish Gowdraddf9a162020-01-27 12:56:27 +05301/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "core_utils.h"
18
19std::string serial_number_to_str(bcmolt_serial_number* serial_number) {
20#define SERIAL_NUMBER_SIZE 12
21 char buff[SERIAL_NUMBER_SIZE+1];
22
23 sprintf(buff, "%c%c%c%c%1X%1X%1X%1X%1X%1X%1X%1X",
24 serial_number->vendor_id.arr[0],
25 serial_number->vendor_id.arr[1],
26 serial_number->vendor_id.arr[2],
27 serial_number->vendor_id.arr[3],
28 serial_number->vendor_specific.arr[0]>>4 & 0x0f,
29 serial_number->vendor_specific.arr[0] & 0x0f,
30 serial_number->vendor_specific.arr[1]>>4 & 0x0f,
31 serial_number->vendor_specific.arr[1] & 0x0f,
32 serial_number->vendor_specific.arr[2]>>4 & 0x0f,
33 serial_number->vendor_specific.arr[2] & 0x0f,
34 serial_number->vendor_specific.arr[3]>>4 & 0x0f,
35 serial_number->vendor_specific.arr[3] & 0x0f);
36
37 return buff;
38}
39
40std::string vendor_specific_to_str(char const * const vendor_specific) {
41 char buff[SERIAL_NUMBER_SIZE+1];
42
43 sprintf(buff, "%1X%1X%1X%1X%1X%1X%1X%1X",
44 vendor_specific[0]>>4 & 0x0f,
45 vendor_specific[0] & 0x0f,
46 vendor_specific[1]>>4 & 0x0f,
47 vendor_specific[1] & 0x0f,
48 vendor_specific[2]>>4 & 0x0f,
49 vendor_specific[2] & 0x0f,
50 vendor_specific[3]>>4 & 0x0f,
51 vendor_specific[3] & 0x0f);
52
53 return buff;
54}
55/**
56* Returns the default NNI (Upstream direction) or PON (Downstream direction) scheduler
57* Every NNI port and PON port have default scheduler.
58* The NNI0 default scheduler ID is 18432, and NNI1 is 18433 and so on.
59* Similarly, PON0 default scheduler ID is 16384. PON1 is 16385 and so on.
60*
61* @param intf_id NNI or PON interface ID
62* @param direction "upstream" or "downstream"
63*
64* @return default scheduler ID for the given interface.
65*/
66
67uint16_t get_dev_id(void) {
68 return dev_id;
69}
70
71int get_default_tm_sched_id(int intf_id, std::string direction) {
72 if (direction.compare(upstream) == 0) {
73 return tm_upstream_sched_id_start + intf_id;
74 } else if (direction.compare(downstream) == 0) {
75 return tm_downstream_sched_id_start + intf_id;
76 }
77 else {
78 OPENOLT_LOG(ERROR, openolt_log_id, "invalid direction - %s\n", direction.c_str());
79 return 0;
80 }
81}
82
83/**
84* Gets a unique tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
85* The tm_sched_id is locally cached in a map, so that it can rendered when necessary.
Burak Gurdag2f2618c2020-04-23 13:20:30 +000086* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem.
87* Note that tech_profile_id is used to differentiate service schedulers in downstream direction.
Girish Gowdraddf9a162020-01-27 12:56:27 +053088*
89* @param intf_id NNI or PON intf ID
90* @param onu_id ONU ID
91* @param uni_id UNI ID
92* @param gemport_id GEM Port ID
93* @param direction Upstream or downstream
Burak Gurdag2f2618c2020-04-23 13:20:30 +000094* @param tech_profile_id Technology Profile ID
Girish Gowdraddf9a162020-01-27 12:56:27 +053095*
96* @return tm_sched_id
97*/
Burak Gurdag2f2618c2020-04-23 13:20:30 +000098uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
99 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530100 int sched_id = -1;
101
102 std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
103 if (it != sched_map.end()) {
104 sched_id = it->second;
105 }
106 if (sched_id != -1) {
107 return sched_id;
108 }
109
110 bcmos_fastlock_lock(&data_lock);
111 // Complexity of O(n). Is there better way that can avoid linear search?
112 for (sched_id = 0; sched_id < MAX_TM_SCHED_ID; sched_id++) {
113 if (tm_sched_bitset[sched_id] == 0) {
114 tm_sched_bitset[sched_id] = 1;
115 break;
116 }
117 }
118 bcmos_fastlock_unlock(&data_lock, 0);
119
120 if (sched_id < MAX_TM_SCHED_ID) {
121 bcmos_fastlock_lock(&data_lock);
122 sched_map[key] = sched_id;
123 bcmos_fastlock_unlock(&data_lock, 0);
124 return sched_id;
125 } else {
126 return -1;
127 }
128}
129
130/**
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000131* Free tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction, tech_profile_id
Girish Gowdraddf9a162020-01-27 12:56:27 +0530132*
133* @param intf_id NNI or PON intf ID
134* @param onu_id ONU ID
135* @param uni_id UNI ID
136* @param gemport_id GEM Port ID
137* @param direction Upstream or downstream
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000138* @param tech_profile_id Technology Profile ID
Girish Gowdraddf9a162020-01-27 12:56:27 +0530139*/
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000140void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
141 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530142 std::map<sched_map_key_tuple, int>::const_iterator it;
143 bcmos_fastlock_lock(&data_lock);
144 it = sched_map.find(key);
145 if (it != sched_map.end()) {
146 tm_sched_bitset[it->second] = 0;
147 sched_map.erase(it);
148 }
149 bcmos_fastlock_unlock(&data_lock, 0);
150}
151
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000152bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
153 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530154 std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
155 if (it != sched_map.end()) {
156 return true;
157 }
158 return false;
159}
160
161/**
162* Check whether given two tm qmp profiles are equal or not
163*
164* @param tmq_map_profileA <vector> TM QUEUE MAPPING PROFILE
165* @param tmq_map_profileB <vector> TM QUEUE MAPPING PROFILE
166*
167* @return boolean, true if given tmq_map_profiles are equal else false
168*/
169
170bool check_tm_qmp_equality(std::vector<uint32_t> tmq_map_profileA, std::vector<uint32_t> tmq_map_profileB) {
171 for (uint32_t i = 0; i < TMQ_MAP_PROFILE_SIZE; i++) {
172 if (tmq_map_profileA[i] != tmq_map_profileB[i]) {
173 return false;
174 }
175 }
176 return true;
177}
178
179/**
180* Modifies given queues_pbit_map to parsable format
181* e.g: Modifes "0b00000101" to "10100000"
182*
183* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
184* @param size Queue count
185*
186* @return string queues_pbit_map
187*/
188std::string* get_valid_queues_pbit_map(std::string *queues_pbit_map, uint32_t size) {
189 for(uint32_t i=0; i < size; i++) {
190 /* Deletes 2 characters from index number 0 */
191 queues_pbit_map[i].erase(0, 2);
192 std::reverse(queues_pbit_map[i].begin(), queues_pbit_map[i].end());
193 }
194 return queues_pbit_map;
195}
196
197/**
198* Creates TM QUEUE MAPPING PROFILE for given queues_pbit_map and queues_priority_q
199*
200* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
201* @param queues_priority_q PRIORITY_Q configured for each GEM in TECH PROFILE
202* @param size Queue count
203*
204* @return <vector> TM QUEUE MAPPING PROFILE
205*/
206std::vector<uint32_t> get_tmq_map_profile(std::string *queues_pbit_map, uint32_t *queues_priority_q, uint32_t size) {
207 std::vector<uint32_t> tmq_map_profile(8,0);
208
209 for(uint32_t i=0; i < size; i++) {
210 for (uint32_t j = 0; j < queues_pbit_map[i].size(); j++) {
211 if (queues_pbit_map[i][j]=='1') {
212 tmq_map_profile.at(j) = queue_id_list[queues_priority_q[i]];
213 }
214 }
215 }
216 return tmq_map_profile;
217}
218
219/**
220* Gets corresponding tm_qmp_id for a given tmq_map_profile
221*
222* @param <vector> TM QUEUE MAPPING PROFILE
223*
224* @return tm_qmp_id
225*/
226int get_tm_qmp_id(std::vector<uint32_t> tmq_map_profile) {
227 int tm_qmp_id = -1;
228
229 std::map<int, std::vector < uint32_t > >::const_iterator it = qmp_id_to_qmp_map.begin();
230 while(it != qmp_id_to_qmp_map.end()) {
231 if(check_tm_qmp_equality(tmq_map_profile, it->second)) {
232 tm_qmp_id = it->first;
233 break;
234 }
235 it++;
236 }
237 return tm_qmp_id;
238}
239
240/**
241* Updates sched_qmp_id_map with given sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id
242*
243* @param upstream/downstream sched_id
244* @param PON intf ID
245* @param onu_id ONU ID
246* @param uni_id UNI ID
247* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
248*/
249void update_sched_qmp_id_map(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
250 uint32_t uni_id, int tm_qmp_id) {
251 bcmos_fastlock_lock(&data_lock);
252 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
253 sched_qmp_id_map.insert(make_pair(key, tm_qmp_id));
254 bcmos_fastlock_unlock(&data_lock, 0);
255}
256
257/**
258* Gets corresponding tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
259*
260* @param upstream/downstream sched_id
261* @param PON intf ID
262* @param onu_id ONU ID
263* @param uni_id UNI ID
264*
265* @return tm_qmp_id
266*/
267int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
268 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
269 int tm_qmp_id = -1;
270
271 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
272 if (it != sched_qmp_id_map.end()) {
273 tm_qmp_id = it->second;
274 }
275 return tm_qmp_id;
276}
277
278/**
279* Gets a unique tm_qmp_id for a given tmq_map_profile
280* The tm_qmp_id is locally cached in a map, so that it can be rendered when necessary.
281* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
282*
283* @param upstream/downstream sched_id
284* @param PON intf ID
285* @param onu_id ONU ID
286* @param uni_id UNI ID
287* @param <vector> TM QUEUE MAPPING PROFILE
288*
289* @return tm_qmp_id
290*/
291int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, \
292 std::vector<uint32_t> tmq_map_profile) {
293 int tm_qmp_id;
294
295 bcmos_fastlock_lock(&data_lock);
296 /* Complexity of O(n). Is there better way that can avoid linear search? */
297 for (tm_qmp_id = 0; tm_qmp_id < MAX_TM_QMP_ID; tm_qmp_id++) {
298 if (tm_qmp_bitset[tm_qmp_id] == 0) {
299 tm_qmp_bitset[tm_qmp_id] = 1;
300 break;
301 }
302 }
303 bcmos_fastlock_unlock(&data_lock, 0);
304
305 if (tm_qmp_id < MAX_TM_QMP_ID) {
306 bcmos_fastlock_lock(&data_lock);
307 qmp_id_to_qmp_map.insert(make_pair(tm_qmp_id, tmq_map_profile));
308 bcmos_fastlock_unlock(&data_lock, 0);
309 update_sched_qmp_id_map(sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id);
310 return tm_qmp_id;
311 } else {
312 return -1;
313 }
314}
315
316/**
317* Free tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
318*
319* @param upstream/downstream sched_id
320* @param PON intf ID
321* @param onu_id ONU ID
322* @param uni_id UNI ID
323* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
324*
325* @return boolean, true if no more reference for TM QMP else false
326*/
327bool free_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
328 uint32_t uni_id, int tm_qmp_id) {
329 bool result;
330 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
331 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
332 bcmos_fastlock_lock(&data_lock);
333 if (it != sched_qmp_id_map.end()) {
334 sched_qmp_id_map.erase(it);
335 }
336 bcmos_fastlock_unlock(&data_lock, 0);
337
338 uint32_t tm_qmp_ref_count = 0;
339 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it2 = sched_qmp_id_map.begin();
340 while(it2 != sched_qmp_id_map.end()) {
341 if(it2->second == tm_qmp_id) {
342 tm_qmp_ref_count++;
343 }
344 it2++;
345 }
346
347 if (tm_qmp_ref_count == 0) {
348 std::map<int, std::vector < uint32_t > >::const_iterator it3 = qmp_id_to_qmp_map.find(tm_qmp_id);
349 if (it3 != qmp_id_to_qmp_map.end()) {
350 bcmos_fastlock_lock(&data_lock);
351 tm_qmp_bitset[tm_qmp_id] = 0;
352 qmp_id_to_qmp_map.erase(it3);
353 bcmos_fastlock_unlock(&data_lock, 0);
354 OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So clearing it\n", \
355 tm_qmp_id, tm_qmp_ref_count);
356 result = true;
357 }
358 } else {
359 OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So not clearing it\n", \
360 tm_qmp_id, tm_qmp_ref_count);
361 result = false;
362 }
363 return result;
364}
365
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530366/* ACL ID is a shared resource, caller of this function has to ensure atomicity using locks
367 Gets free ACL ID if available, else -1. */
Girish Gowdraddf9a162020-01-27 12:56:27 +0530368int get_acl_id() {
369 int acl_id;
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530370
Girish Gowdraddf9a162020-01-27 12:56:27 +0530371 /* Complexity of O(n). Is there better way that can avoid linear search? */
372 for (acl_id = 0; acl_id < MAX_ACL_ID; acl_id++) {
373 if (acl_id_bitset[acl_id] == 0) {
374 acl_id_bitset[acl_id] = 1;
375 break;
376 }
377 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530378 if (acl_id < MAX_ACL_ID) {
379 return acl_id ;
380 } else {
381 return -1;
382 }
383}
384
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530385/* ACL ID is a shared resource, caller of this function has to ensure atomicity using locks
386 Frees up the ACL ID. */
Girish Gowdraddf9a162020-01-27 12:56:27 +0530387void free_acl_id (int acl_id) {
388 if (acl_id < MAX_ACL_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530389 acl_id_bitset[acl_id] = 0;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530390 }
391}
392
393/**
394* Returns qos type as string
395*
396* @param qos_type bcmolt_egress_qos_type enum
397*/
398std::string get_qos_type_as_string(bcmolt_egress_qos_type qos_type) {
399 switch (qos_type)
400 {
401 case BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE: return "FIXED_QUEUE";
402 case BCMOLT_EGRESS_QOS_TYPE_TC_TO_QUEUE: return "TC_TO_QUEUE";
403 case BCMOLT_EGRESS_QOS_TYPE_PBIT_TO_TC: return "PBIT_TO_TC";
404 case BCMOLT_EGRESS_QOS_TYPE_NONE: return "NONE";
405 case BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE: return "PRIORITY_TO_QUEUE";
406 default: OPENOLT_LOG(ERROR, openolt_log_id, "qos-type-not-supported %d\n", qos_type);
407 return "qos-type-not-supported";
408 }
409}
410
411/**
412* Gets/Updates qos type for given pon_intf_id, onu_id, uni_id
413*
414* @param PON intf ID
415* @param onu_id ONU ID
416* @param uni_id UNI ID
417* @param queue_size TrafficQueues Size
418*
419* @return qos_type
420*/
421bcmolt_egress_qos_type get_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, uint32_t queue_size) {
422 qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
423 bcmolt_egress_qos_type egress_qos_type = BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
424 std::string qos_string;
425
426 std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
427 if (it != qos_type_map.end()) {
428 egress_qos_type = it->second;
429 qos_string = get_qos_type_as_string(egress_qos_type);
430 OPENOLT_LOG(INFO, openolt_log_id, "Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d is %s\n", \
431 pon_intf_id, onu_id, uni_id, qos_string.c_str());
432 }
433 else {
434 /* QOS Type has been pre-defined as Fixed Queue but it will be updated based on number of GEMPORTS
435 associated for a given subscriber. If GEM count = 1 for a given subscriber, qos_type will be Fixed Queue
436 else Priority to Queue */
437 egress_qos_type = (queue_size > 1) ? \
438 BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE : BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
439 bcmos_fastlock_lock(&data_lock);
440 qos_type_map.insert(make_pair(key, egress_qos_type));
441 bcmos_fastlock_unlock(&data_lock, 0);
442 qos_string = get_qos_type_as_string(egress_qos_type);
443 OPENOLT_LOG(INFO, openolt_log_id, "Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d is %s\n", \
444 pon_intf_id, onu_id, uni_id, qos_string.c_str());
445 }
446 return egress_qos_type;
447}
448
449/**
450* Clears qos type for given pon_intf_id, onu_id, uni_id
451*
452* @param PON intf ID
453* @param onu_id ONU ID
454* @param uni_id UNI ID
455*/
456void clear_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
457 qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
458 std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
459 bcmos_fastlock_lock(&data_lock);
460 if (it != qos_type_map.end()) {
461 qos_type_map.erase(it);
462 OPENOLT_LOG(INFO, openolt_log_id, "Cleared Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d\n", \
463 pon_intf_id, onu_id, uni_id);
464 }
465 bcmos_fastlock_unlock(&data_lock, 0);
466}
467
468/**
469* Returns Scheduler/Queue direction as string
470*
471* @param direction as specified in tech_profile.proto
472*/
473std::string GetDirection(int direction) {
474 switch (direction)
475 {
476 case tech_profile::Direction::UPSTREAM: return upstream;
477 case tech_profile::Direction::DOWNSTREAM: return downstream;
478 default: OPENOLT_LOG(ERROR, openolt_log_id, "direction-not-supported %d\n", direction);
479 return "direction-not-supported";
480 }
481}
482
483// This method handles waiting for AllocObject configuration.
484// Returns error if the AllocObject is not in the appropriate state based on action requested.
485bcmos_errno wait_for_alloc_action(uint32_t intf_id, uint32_t alloc_id, AllocCfgAction action) {
486 Queue<alloc_cfg_complete_result> cfg_result;
487 alloc_cfg_compltd_key k(intf_id, alloc_id);
488 alloc_cfg_compltd_map[k] = &cfg_result;
489 bcmos_errno err = BCM_ERR_OK;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530490
491 // Try to pop the result from BAL with a timeout of ALLOC_CFG_COMPLETE_WAIT_TIMEOUT ms
492 std::pair<alloc_cfg_complete_result, bool> result = cfg_result.pop(ALLOC_CFG_COMPLETE_WAIT_TIMEOUT);
493 if (result.second == false) {
494 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for alloc cfg complete indication intf_id %d, alloc_id %d\n",
495 intf_id, alloc_id);
496 // Invalidate the queue pointer.
497 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
498 alloc_cfg_compltd_map[k] = NULL;
499 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
500 err = BCM_ERR_INTERNAL;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530501 }
502 else if (result.first.status == ALLOC_CFG_STATUS_FAIL) {
503 OPENOLT_LOG(ERROR, openolt_log_id, "error processing alloc cfg request intf_id %d, alloc_id %d\n",
504 intf_id, alloc_id);
505 err = BCM_ERR_INTERNAL;
506 }
507
508 if (err == BCM_ERR_OK) {
509 if (action == ALLOC_OBJECT_CREATE) {
510 if (result.first.state != ALLOC_OBJECT_STATE_ACTIVE) {
511 OPENOLT_LOG(ERROR, openolt_log_id, "alloc object not in active state intf_id %d, alloc_id %d alloc_obj_state %d\n",
512 intf_id, alloc_id, result.first.state);
513 err = BCM_ERR_INTERNAL;
514 } else {
515 OPENOLT_LOG(INFO, openolt_log_id, "Create upstream bandwidth allocation success, intf_id %d, alloc_id %d\n",
516 intf_id, alloc_id);
517 }
518 } else { // ALLOC_OBJECT_DELETE
519 if (result.first.state != ALLOC_OBJECT_STATE_NOT_CONFIGURED) {
520 OPENOLT_LOG(ERROR, openolt_log_id, "alloc object is not reset intf_id %d, alloc_id %d alloc_obj_state %d\n",
521 intf_id, alloc_id, result.first.state);
522 err = BCM_ERR_INTERNAL;
523 } else {
524 OPENOLT_LOG(INFO, openolt_log_id, "Remove alloc object success, intf_id %d, alloc_id %d\n",
525 intf_id, alloc_id);
526 }
527 }
528 }
529
530 // Remove entry from map
531 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
532 alloc_cfg_compltd_map.erase(k);
533 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
Girish Gowdra7a79dae2020-02-10 18:22:11 +0530534 return err;
535}
536
537// This method handles waiting for OnuDeactivate Completed Indication
538bcmos_errno wait_for_onu_deactivate_complete(uint32_t intf_id, uint32_t onu_id) {
539 Queue<onu_deactivate_complete_result> deact_result;
540 onu_deact_compltd_key k(intf_id, onu_id);
541 onu_deact_compltd_map[k] = &deact_result;
542 bcmos_errno err = BCM_ERR_OK;
543
544 // Try to pop the result from BAL with a timeout of ONU_DEACTIVATE_COMPLETE_WAIT_TIMEOUT ms
545 std::pair<onu_deactivate_complete_result, bool> result = deact_result.pop(ONU_DEACTIVATE_COMPLETE_WAIT_TIMEOUT);
546 if (result.second == false) {
547 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for onu deactivate complete indication intf_id %d, onu_id %d\n",
548 intf_id, onu_id);
549 // Invalidate the queue pointer.
550 bcmos_fastlock_lock(&onu_deactivate_wait_lock);
551 onu_deact_compltd_map[k] = NULL;
552 bcmos_fastlock_unlock(&onu_deactivate_wait_lock, 0);
553 err = BCM_ERR_INTERNAL;
554 }
555 else if (result.first.result == BCMOLT_RESULT_FAIL) {
556 OPENOLT_LOG(ERROR, openolt_log_id, "error processing onu deactivate request intf_id %d, onu_id %d, fail_reason %d\n",
557 intf_id, onu_id, result.first.reason);
558 err = BCM_ERR_INTERNAL;
559 } else if (result.first.result == BCMOLT_RESULT_SUCCESS) {
560 OPENOLT_LOG(INFO, openolt_log_id, "success processing onu deactivate request intf_id %d, onu_id %d\n",
561 intf_id, onu_id);
562 }
563
564 // Remove entry from map
565 bcmos_fastlock_lock(&onu_deactivate_wait_lock);
566 onu_deact_compltd_map.erase(k);
567 bcmos_fastlock_unlock(&onu_deactivate_wait_lock, 0);
568
Girish Gowdraddf9a162020-01-27 12:56:27 +0530569 return err;
570}
571
572char* openolt_read_sysinfo(const char* field_name, char* field_val)
573{
574 FILE *fp;
575 /* Prepare the command*/
576 char command[150];
577
578 snprintf(command, sizeof command, "bash -l -c \"onlpdump -s\" | perl -ne 'print $1 if /%s: (\\S+)/'", field_name);
579 /* Open the command for reading. */
580 fp = popen(command, "r");
581 if (fp == NULL) {
582 /*The client has to check for a Null field value in this case*/
583 OPENOLT_LOG(INFO, openolt_log_id, "Failed to query the %s\n", field_name);
584 return field_val;
585 }
586
587 /*Read the field value*/
588 if (fp) {
589 uint8_t ret;
590 ret = fread(field_val, OPENOLT_FIELD_LEN, 1, fp);
591 if (ret >= OPENOLT_FIELD_LEN)
592 OPENOLT_LOG(INFO, openolt_log_id, "Read data length %u\n", ret);
593 pclose(fp);
594 }
595 return field_val;
596}
597
598Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state)
599{
600 openolt::Indication ind;
601 openolt::IntfOperIndication* intf_oper_ind = new openolt::IntfOperIndication;
602
603 intf_oper_ind->set_type(type);
604 intf_oper_ind->set_intf_id(intf_id);
605 intf_oper_ind->set_oper_state(state);
606 ind.set_allocated_intf_oper_ind(intf_oper_ind);
607 oltIndQ.push(ind);
608 return Status::OK;
609}
610
611#define CLI_HOST_PROMPT_FORMAT "BCM.%u> "
612
613/* Build CLI prompt */
614void openolt_cli_get_prompt_cb(bcmcli_session *session, char *buf, uint32_t max_len)
615{
616 snprintf(buf, max_len, CLI_HOST_PROMPT_FORMAT, dev_id);
617}
618
619int _bal_apiend_cli_thread_handler(long data)
620{
621 char init_string[]="\n";
622 bcmcli_session *sess = current_session;
623 bcmos_task_parm bal_cli_task_p_dummy;
624
625 /* Switch to interactive mode if not stopped in the init script */
626 if (!bcmcli_is_stopped(sess)) {
627 /* Force a CLI command prompt
628 * The string passed into the parse function
629 * must be modifiable, so a string constant like
630 * bcmcli_parse(current_session, "\n") will not
631 * work.
632 */
633 bcmcli_parse(sess, init_string);
634
635 /* Process user input until EOF or quit command */
636 bcmcli_driver(sess);
637 }
638 OPENOLT_LOG(INFO, openolt_log_id, "BAL API End CLI terminated\n");
639
640 /* Cleanup */
641 bcmcli_session_close(current_session);
642 bcmcli_token_destroy(NULL);
643 return 0;
644}
645
646/* Init API CLI commands for the current device */
647bcmos_errno bcm_openolt_api_cli_init(bcmcli_entry *parent_dir, bcmcli_session *session)
648{
649 bcmos_errno rc;
650
651 api_parent_dir = parent_dir;
652
653 rc = bcm_api_cli_set_commands(session);
654
655#ifdef BCM_SUBSYSTEM_HOST
656 /* Subscribe for device change indication */
657 rc = rc ? rc : bcmolt_olt_sel_ind_register(_api_cli_olt_change_ind);
658#endif
659
660 return rc;
661}
662
663bcmos_errno bcm_cli_quit(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
664{
665 bcmcli_stop(session);
666 bcmcli_session_print(session, "CLI terminated by 'Quit' command\n");
667 status_bcm_cli_quit = BCMOS_TRUE;
668
669 return BCM_ERR_OK;
670}
671
672int get_status_bcm_cli_quit(void) {
673 return status_bcm_cli_quit;
674}
675
676bcmos_errno bcmolt_apiend_cli_init() {
677 bcmos_errno ret;
678 bcmos_task_parm bal_cli_task_p = {};
679 bcmos_task_parm bal_cli_task_p_dummy;
680
681 /** before creating the task, check if it is already created by the other half of BAL i.e. Core side */
682 if (BCM_ERR_OK != bcmos_task_query(&bal_cli_thread, &bal_cli_task_p_dummy)) {
683 /* Create BAL CLI thread */
684 bal_cli_task_p.name = bal_cli_thread_name;
685 bal_cli_task_p.handler = _bal_apiend_cli_thread_handler;
686 bal_cli_task_p.priority = TASK_PRIORITY_CLI;
687
688 ret = bcmos_task_create(&bal_cli_thread, &bal_cli_task_p);
689 if (BCM_ERR_OK != ret) {
690 bcmos_printf("Couldn't create BAL API end CLI thread\n");
691 return ret;
692 }
693 }
694}
695
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530696bcmos_errno get_onu_status(bcmolt_interface pon_ni, int onu_id, bcmolt_onu_state *onu_state) {
697 bcmos_errno err;
698 bcmolt_onu_cfg onu_cfg;
699 bcmolt_onu_key onu_key;
700 onu_key.pon_ni = pon_ni;
701 onu_key.onu_id = onu_id;
702
703 BCMOLT_CFG_INIT(&onu_cfg, onu, onu_key);
704 BCMOLT_FIELD_SET_PRESENT(&onu_cfg.data, onu_cfg_data, onu_state);
705 BCMOLT_FIELD_SET_PRESENT(&onu_cfg.data, onu_cfg_data, itu);
706 #ifdef TEST_MODE
707 // It is impossible to mock the setting of onu_cfg.data.onu_state because
708 // the actual bcmolt_cfg_get passes the address of onu_cfg.hdr and we cannot
709 // set the onu_cfg.data.onu_state. So a new stub function is created and address
710 // of onu_cfg is passed. This is one-of case where we need to add test specific
711 // code in production code.
712 err = bcmolt_cfg_get__onu_state_stub(dev_id, &onu_cfg);
713 #else
714 err = bcmolt_cfg_get(dev_id, &onu_cfg.hdr);
715 #endif
716 *onu_state = onu_cfg.data.onu_state;
717 return err;
718}
719
720bcmos_errno get_pon_interface_status(bcmolt_interface pon_ni, bcmolt_interface_state *state, bcmolt_status *los_status) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530721 bcmos_errno err;
722 bcmolt_pon_interface_key pon_key;
723 bcmolt_pon_interface_cfg pon_cfg;
724 pon_key.pon_ni = pon_ni;
725
726 BCMOLT_CFG_INIT(&pon_cfg, pon_interface, pon_key);
727 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, state);
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530728 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, los_status);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530729 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, itu);
730 #ifdef TEST_MODE
731 // It is impossible to mock the setting of pon_cfg.data.state because
732 // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
733 // set the pon_cfg.data.state. So a new stub function is created and address
734 // of pon_cfg is passed. This is one-of case where we need to add test specific
735 // code in production code.
736 err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
737 #else
738 err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
739 #endif
740 *state = pon_cfg.data.state;
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530741 *los_status = pon_cfg.data.los_status;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530742 return err;
743}
744
745/* Same as bcmolt_cfg_get but with added logic of retrying the API
746 in case of some specific failures like timeout or object not yet ready
747*/
748bcmos_errno bcmolt_cfg_get_mult_retry(bcmolt_oltid olt, bcmolt_cfg *cfg) {
749 bcmos_errno err;
750 uint32_t current_try = 0;
751
752 while (current_try < MAX_BAL_API_RETRY_COUNT) {
753 err = bcmolt_cfg_get(olt, cfg);
754 current_try++;
755
756 if (err == BCM_ERR_STATE || err == BCM_ERR_TIMEOUT) {
757 OPENOLT_LOG(WARNING, openolt_log_id, "bcmolt_cfg_get: err = %s\n", bcmos_strerror(err));
758 bcmos_usleep(BAL_API_RETRY_TIME_IN_USECS);
759 continue;
760 }
761 else {
762 break;
763 }
764 }
765
766 if (err != BCM_ERR_OK) {
767 OPENOLT_LOG(ERROR, openolt_log_id, "bcmolt_cfg_get tried (%d) times with retry time(%d usecs) err = %s\n",
768 current_try,
769 BAL_API_RETRY_TIME_IN_USECS,
770 bcmos_strerror(err));
771 }
772 return err;
773}
774
775
776unsigned NumNniIf_() {return num_of_nni_ports;}
777unsigned NumPonIf_() {return num_of_pon_ports;}
778
779bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state) {
780 bcmos_errno err;
781 bcmolt_nni_interface_key nni_key;
782 bcmolt_nni_interface_cfg nni_cfg;
783 nni_key.id = id;
784
785 BCMOLT_CFG_INIT(&nni_cfg, nni_interface, nni_key);
786 BCMOLT_FIELD_SET_PRESENT(&nni_cfg.data, nni_interface_cfg_data, state);
787 #ifdef TEST_MODE
788 // It is impossible to mock the setting of nni_cfg.data.state because
789 // the actual bcmolt_cfg_get passes the address of nni_cfg.hdr and we cannot
790 // set the nni_cfg.data.state. So a new stub function is created and address
791 // of nni_cfg is passed. This is one-of case where we need to add test specific
792 // code in production code.
793 err = bcmolt_cfg_get__nni_intf_stub(dev_id, &nni_cfg);
794 #else
795 err = bcmolt_cfg_get(dev_id, &nni_cfg.hdr);
796 #endif
797 *state = nni_cfg.data.state;
798 return err;
799}
800
801Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t gemport_id) {
802 bcmos_errno err;
803 bcmolt_itupon_gem_cfg cfg; /* declare main API struct */
804 bcmolt_itupon_gem_key key = {}; /* declare key */
805 bcmolt_gem_port_configuration configuration = {};
806
807 key.pon_ni = intf_id;
808 key.gem_port_id = gemport_id;
809
810 BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
811
812 bcmolt_gem_port_direction configuration_direction;
813 configuration_direction = BCMOLT_GEM_PORT_DIRECTION_BIDIRECTIONAL;
814 BCMOLT_FIELD_SET(&configuration, gem_port_configuration, direction, configuration_direction);
815
816 bcmolt_gem_port_type configuration_type;
817 configuration_type = BCMOLT_GEM_PORT_TYPE_UNICAST;
818 BCMOLT_FIELD_SET(&configuration, gem_port_configuration, type, configuration_type);
819
820 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, configuration, configuration);
821
822 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, onu_id, onu_id);
823
824 bcmolt_control_state encryption_mode;
825 encryption_mode = BCMOLT_CONTROL_STATE_DISABLE;
826 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
827
828 bcmolt_us_gem_port_destination upstream_destination_queue;
829 upstream_destination_queue = BCMOLT_US_GEM_PORT_DESTINATION_DATA;
830 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, upstream_destination_queue, upstream_destination_queue);
831
832 bcmolt_control_state control;
833 control = BCMOLT_CONTROL_STATE_ENABLE;
834 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, control, control);
835
836 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
837 if(err != BCM_ERR_OK) {
838 OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d\n", gemport_id);
839 return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
840 }
841
842 OPENOLT_LOG(INFO, openolt_log_id, "gem port installed successfully = %d\n", gemport_id);
843
844 return Status::OK;
845}
846
847Status remove_gem_port(int32_t intf_id, int32_t gemport_id) {
848 bcmolt_itupon_gem_cfg gem_cfg;
849 bcmolt_itupon_gem_key key = {
850 .pon_ni = (bcmolt_interface)intf_id,
851 .gem_port_id = (bcmolt_gem_port_id)gemport_id
852 };
853 bcmos_errno err;
854
855 BCMOLT_CFG_INIT(&gem_cfg, itupon_gem, key);
856 err = bcmolt_cfg_clear(dev_id, &gem_cfg.hdr);
857 if (err != BCM_ERR_OK)
858 {
859 OPENOLT_LOG(ERROR, openolt_log_id, "failed to remove gem_port = %d err=%s\n", gemport_id, gem_cfg.hdr.hdr.err_text);
860 return bcm_to_grpc_err(err, "Access_Control clear ITU PON Gem port failed");
861 }
862
863 OPENOLT_LOG(INFO, openolt_log_id, "gem port removed successfully = %d\n", gemport_id);
864
865 return Status::OK;
866}
867
868Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
869 bcmolt_members_update_command acl_cmd) {
870 bcmos_errno err;
871 bcmolt_access_control_interfaces_update oper; /* declare main API struct */
872 bcmolt_access_control_key acl_key = {}; /* declare key */
873 bcmolt_intf_ref interface_ref_list_elem = {};
874 bcmolt_interface_type interface_ref_list_elem_intf_type;
875 bcmolt_interface_id interface_ref_list_elem_intf_id;
876 bcmolt_intf_ref_list_u8 interface_ref_list = {};
877
878 if (acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_ADD && acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) {
879 OPENOLT_LOG(ERROR, openolt_log_id, "acl cmd = %d not supported currently\n", acl_cmd);
880 return bcm_to_grpc_err(BCM_ERR_PARM, "unsupported acl cmd");
881 }
882 interface_ref_list.arr = (bcmolt_intf_ref*)bcmos_calloc(sizeof(bcmolt_intf_ref)*1);
883
884 if (interface_ref_list.arr == NULL)
885 return bcm_to_grpc_err(BCM_ERR_PARM, "allocate interface_ref_list failed");
886 OPENOLT_LOG(INFO, openolt_log_id, "update acl interface received for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
887 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
888 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
889
890 acl_key.id = access_control_id;
891
892 /* Initialize the API struct. */
893 BCMOLT_OPER_INIT(&oper, access_control, interfaces_update, acl_key);
894
895 bcmolt_members_update_command command;
896 command = acl_cmd;
897 BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, command, command);
898
899 interface_ref_list_elem_intf_type = intf_type;
900 BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_type, interface_ref_list_elem_intf_type);
901
902 interface_ref_list_elem_intf_id = intf_id;
903 BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_id, interface_ref_list_elem_intf_id);
904
905 interface_ref_list.len = 1;
906 BCMOLT_ARRAY_ELEM_SET(&interface_ref_list, 0, interface_ref_list_elem);
907
908 BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, interface_ref_list, interface_ref_list);
909
910 err = bcmolt_oper_submit(dev_id, &oper.hdr);
911 if (err != BCM_ERR_OK) {
912 OPENOLT_LOG(ERROR, openolt_log_id, "update acl interface fail for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
913 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
914 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
915 return bcm_to_grpc_err(err, "Access_Control submit interface failed");
916 }
917
918 bcmos_free(interface_ref_list.arr);
919 OPENOLT_LOG(INFO, openolt_log_id, "update acl interface success for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
920 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
921 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
922
923 return Status::OK;
924}
925
926Status install_acl(const acl_classifier_key acl_key) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530927 bcmos_errno err;
928 bcmolt_access_control_cfg cfg;
929 bcmolt_access_control_key key = { };
930 bcmolt_classifier c_val = { };
931 // hardcode the action for now.
932 bcmolt_access_control_fwd_action_type action_type = BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST;
933
934 int acl_id = get_acl_id();
935 if (acl_id < 0) {
936 OPENOLT_LOG(ERROR, openolt_log_id, "exhausted acl_id for eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d\n",
937 acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530938 return bcm_to_grpc_err(BCM_ERR_INTERNAL, "exhausted acl id");
939 }
940
941 key.id = acl_id;
942 /* config access control instance */
943 BCMOLT_CFG_INIT(&cfg, access_control, key);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530944 if (acl_key.ether_type > 0) {
945 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ether_type 0x%04x\n", acl_key.ether_type);
946 BCMOLT_FIELD_SET(&c_val, classifier, ether_type, acl_key.ether_type);
947 }
948
949 if (acl_key.ip_proto > 0) {
950 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ip_proto %d\n", acl_key.ip_proto);
951 BCMOLT_FIELD_SET(&c_val, classifier, ip_proto, acl_key.ip_proto);
952 }
953
954 if (acl_key.dst_port > 0) {
955 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify dst_port %d\n", acl_key.dst_port);
956 BCMOLT_FIELD_SET(&c_val, classifier, dst_port, acl_key.dst_port);
957 }
958
959 if (acl_key.src_port > 0) {
960 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify src_port %d\n", acl_key.src_port);
961 BCMOLT_FIELD_SET(&c_val, classifier, src_port, acl_key.src_port);
962 }
963
964 BCMOLT_MSG_FIELD_SET(&cfg, classifier, c_val);
965 BCMOLT_MSG_FIELD_SET(&cfg, priority, 10000);
966 BCMOLT_MSG_FIELD_SET(&cfg, statistics_control, BCMOLT_CONTROL_STATE_ENABLE);
967
968 BCMOLT_MSG_FIELD_SET(&cfg, forwarding_action.action, action_type);
969
970 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
971 if (err != BCM_ERR_OK) {
972 OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control set configuration failed, Error %d\n", err);
973 // Free the acl_id
974 free_acl_id(acl_id);
975 return bcm_to_grpc_err(err, "Access_Control set configuration failed");
976 }
977
978 ACL_LOG(INFO, "ACL add ok", err);
979
980 // Update the map that we have installed an acl for the given classfier.
981 acl_classifier_to_acl_id_map[acl_key] = acl_id;
982 return Status::OK;
983}
984
985Status remove_acl(int acl_id) {
986 bcmos_errno err;
987 bcmolt_access_control_cfg cfg; /* declare main API struct */
988 bcmolt_access_control_key key = {}; /* declare key */
989
990 key.id = acl_id;
991
992 /* Initialize the API struct. */
993 BCMOLT_CFG_INIT(&cfg, access_control, key);
994 BCMOLT_FIELD_SET_PRESENT(&cfg.data, access_control_cfg_data, state);
995 err = bcmolt_cfg_get(dev_id, &cfg.hdr);
996 if (err != BCM_ERR_OK) {
997 OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control get state failed\n");
998 return bcm_to_grpc_err(err, "Access_Control get state failed");
999 }
1000
1001 if (cfg.data.state == BCMOLT_CONFIG_STATE_CONFIGURED) {
1002 key.id = acl_id;
1003 /* Initialize the API struct. */
1004 BCMOLT_CFG_INIT(&cfg, access_control, key);
1005
1006 err = bcmolt_cfg_clear(dev_id, &cfg.hdr);
1007 if (err != BCM_ERR_OK) {
1008 // Should we free acl_id here ? We should ideally never land here..
1009 OPENOLT_LOG(ERROR, openolt_log_id, "Error %d while removing Access_Control rule ID %d\n",
1010 err, acl_id);
1011 return Status(grpc::StatusCode::INTERNAL, "Failed to remove Access_Control");
1012 }
1013 }
1014
1015 // Free up acl_id
1016 free_acl_id(acl_id);
1017
1018 OPENOLT_LOG(INFO, openolt_log_id, "acl removed successfully %d\n", acl_id);
1019
1020 return Status::OK;
1021}
1022
1023// Formulates ACL Classifier Key based on the following fields
1024// a. ether_type b. ip_proto c. src_port d. dst_port
1025// If any of the field is not available it is populated as -1.
1026void formulate_acl_classifier_key(acl_classifier_key *key, const ::openolt::Classifier& classifier) {
1027
1028 // TODO: Is 0 a valid value for any of the following classifiers?
1029 // because in the that case, the 'if' check would fail and -1 would be filled as value.
1030 //
1031 if (classifier.eth_type()) {
1032 OPENOLT_LOG(DEBUG, openolt_log_id, "classify ether_type 0x%04x\n", classifier.eth_type());
1033 key->ether_type = classifier.eth_type();
1034 } else key->ether_type = -1;
1035
1036 if (classifier.ip_proto()) {
1037 OPENOLT_LOG(DEBUG, openolt_log_id, "classify ip_proto %d\n", classifier.ip_proto());
1038 key->ip_proto = classifier.ip_proto();
1039 } else key->ip_proto = -1;
1040
1041
1042 if (classifier.src_port()) {
1043 OPENOLT_LOG(DEBUG, openolt_log_id, "classify src_port %d\n", classifier.src_port());
1044 key->src_port = classifier.src_port();
1045 } else key->src_port = -1;
1046
1047
1048 if (classifier.dst_port()) {
1049 OPENOLT_LOG(DEBUG, openolt_log_id, "classify dst_port %d\n", classifier.dst_port());
1050 key->dst_port = classifier.dst_port();
1051 } else key->dst_port = -1;
1052}
1053
1054Status handle_acl_rule_install(int32_t onu_id, uint32_t flow_id,
1055 const std::string flow_type, int32_t access_intf_id,
1056 int32_t network_intf_id, int32_t gemport_id,
1057 const ::openolt::Classifier& classifier) {
1058 int acl_id;
1059 int32_t intf_id = flow_type.compare(upstream) == 0? access_intf_id: network_intf_id;
1060 const std::string intf_type = flow_type.compare(upstream) == 0? "pon": "nni";
1061 bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
1062
1063 Status resp;
1064
1065 // few map keys we are going to use later.
1066 flow_id_flow_direction fl_id_fl_dir(flow_id, flow_type);
1067 gem_id_intf_id gem_intf(gemport_id, access_intf_id);
1068 acl_classifier_key acl_key;
1069 formulate_acl_classifier_key(&acl_key, classifier);
1070 const acl_classifier_key acl_key_const = {.ether_type=acl_key.ether_type, .ip_proto=acl_key.ip_proto,
1071 .src_port=acl_key.src_port, .dst_port=acl_key.dst_port};
1072
1073 bcmos_fastlock_lock(&data_lock);
1074
1075 // Check if the acl is already installed
1076 if (acl_classifier_to_acl_id_map.count(acl_key_const) > 0) {
1077 // retreive the acl_id
1078 acl_id = acl_classifier_to_acl_id_map[acl_key_const];
1079 acl_id_gem_id_intf_id ac_id_gm_id_if_id(acl_id, gemport_id, intf_id);
1080 if (flow_to_acl_map.count(fl_id_fl_dir)) {
1081 // coult happen if same trap flow is received again
1082 OPENOLT_LOG(INFO, openolt_log_id, "flow and related acl already handled, nothing more to do\n");
1083 bcmos_fastlock_unlock(&data_lock, 0);
1084 return Status::OK;
1085 }
1086
1087 OPENOLT_LOG(INFO, openolt_log_id, "Acl for flow_id=%u with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d already installed with acl id = %u\n",
1088 flow_id, acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port, acl_id);
1089
1090 // The acl_ref_cnt is needed to know how many flows refer an ACL.
1091 // When the flow is removed, we decrement the reference count.
1092 // When the reference count becomes 0, we remove the ACL.
1093 if (acl_ref_cnt.count(acl_id) > 0) {
1094 acl_ref_cnt[acl_id] ++;
1095 } else {
1096 // We should ideally not land here. The acl_ref_cnt should have been
1097 // initialized the first time acl was installed.
1098 acl_ref_cnt[acl_id] = 1;
1099 }
1100
1101 } else {
1102 resp = install_acl(acl_key_const);
1103 if (!resp.ok()) {
1104 OPENOLT_LOG(ERROR, openolt_log_id, "Acl for flow_id=%u with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d failed\n",
1105 flow_id, acl_key_const.ether_type, acl_key_const.ip_proto, acl_key_const.src_port, acl_key_const.dst_port);
1106 bcmos_fastlock_unlock(&data_lock, 0);
1107 return resp;
1108 }
1109
1110 acl_id = acl_classifier_to_acl_id_map[acl_key_const];
1111
1112 // Initialize the acl reference count
1113 acl_ref_cnt[acl_id] = 1;
1114
1115 OPENOLT_LOG(INFO, openolt_log_id, "acl add success for flow_id=%u with acl_id=%d\n", flow_id, acl_id);
1116 }
1117
1118 // Register the interface for the given acl
1119 acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
1120 // This is needed to keep a track of which interface (pon/nni) has registered for an ACL.
1121 // If it is registered, how many flows refer to it.
1122 if (intf_acl_registration_ref_cnt.count(ac_id_inf_id_inf_type) > 0) {
1123 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]++;
1124 } else {
1125 // The given interface is not registered for the ACL. We need to do it now.
1126 resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_ADD);
1127 if (!resp.ok()){
1128 OPENOLT_LOG(ERROR, openolt_log_id, "failed to update acl interfaces intf_id=%d, intf_type=%s, acl_id=%d", intf_id, intf_type.c_str(), acl_id);
1129 // TODO: Ideally we should return error from hear and clean up other other stateful
1130 // counters we creaed earlier. Will leave it out for now.
1131 }
1132 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] = 1;
1133 }
1134
1135
1136 // Install the gem port if needed.
1137 if (gemport_id > 0 && access_intf_id >= 0) {
1138 if (gem_ref_cnt.count(gem_intf) > 0) {
1139 // The gem port is already installed
1140 // Increment the ref counter indicating number of flows referencing this gem port
1141 gem_ref_cnt[gem_intf]++;
1142 OPENOLT_LOG(DEBUG, openolt_log_id, "increment gem_ref_cnt in acl handler, ref_cnt=%d\n", gem_ref_cnt[gem_intf]);
1143
1144 } else {
1145 // We should ideally never land here. The gem port should have been created the
1146 // first time ACL was installed.
1147 // Install the gem port
1148 Status resp = install_gem_port(access_intf_id, onu_id, gemport_id);
1149 if (!resp.ok()) {
1150 // TODO: We might need to reverse all previous data, but leave it out for now.
1151 OPENOLT_LOG(ERROR, openolt_log_id, "failed to install the gemport=%d for acl_id=%d, intf_id=%d\n", gemport_id, acl_id, access_intf_id);
1152 bcmos_fastlock_unlock(&data_lock, 0);
1153 return resp;
1154 }
1155 // Initialize the refence count for the gemport.
1156 gem_ref_cnt[gem_intf] = 1;
1157 OPENOLT_LOG(DEBUG, openolt_log_id, "intialized gem ref count in acl handler\n");
1158 }
1159 } else {
1160 OPENOLT_LOG(DEBUG, openolt_log_id, "not incrementing gem_ref_cnt in acl handler flow_id=%d, gemport_id=%d, intf_id=%d\n", flow_id, gemport_id, access_intf_id);
1161 }
1162
1163 // Update the flow_to_acl_map
1164 // This info is needed during flow remove. We need to which ACL ID and GEM PORT ID
1165 // the flow was referring to.
1166 // After retrieving the ACL ID and GEM PORT ID, we decrement the corresponding
1167 // reference counters for those ACL ID and GEMPORT ID.
1168 acl_id_gem_id_intf_id ac_id_gm_id_if_id(acl_id, gemport_id, intf_id);
1169 flow_to_acl_map[fl_id_fl_dir] = ac_id_gm_id_if_id;
1170
1171 bcmos_fastlock_unlock(&data_lock, 0);
1172
1173 return Status::OK;
1174}
1175
1176void clear_gem_port(int gemport_id, int access_intf_id) {
1177 gem_id_intf_id gem_intf(gemport_id, access_intf_id);
1178 if (gemport_id > 0 && access_intf_id >= 0 && gem_ref_cnt.count(gem_intf) > 0) {
1179 OPENOLT_LOG(DEBUG, openolt_log_id, "decrementing gem_ref_cnt gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
1180 gem_ref_cnt[gem_intf]--;
1181 if (gem_ref_cnt[gem_intf] == 0) {
1182 // For datapath flow this may not be necessary (to be verified)
1183 remove_gem_port(access_intf_id, gemport_id);
1184 gem_ref_cnt.erase(gem_intf);
1185 OPENOLT_LOG(DEBUG, openolt_log_id, "removing gem_ref_cnt entry gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
1186 } else {
1187 OPENOLT_LOG(DEBUG, openolt_log_id, "gem_ref_cnt not zero yet gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
1188 }
1189 } else {
1190 OPENOLT_LOG(DEBUG, openolt_log_id, "not decrementing gem_ref_cnt gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
1191 }
1192}
1193
1194Status handle_acl_rule_cleanup(int16_t acl_id, int32_t gemport_id, int32_t intf_id, const std::string flow_type) {
1195 const std::string intf_type= flow_type.compare(upstream) == 0 ? "pon": "nni";
1196 acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
1197 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]--;
1198 if (intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] == 0) {
1199 bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
1200 Status resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE);
1201 if (!resp.ok()){
1202 OPENOLT_LOG(ERROR, openolt_log_id, "failed to update acl interfaces intf_id=%d, intf_type=%s, acl_id=%d", intf_id, intf_type.c_str(), acl_id);
1203 }
1204 intf_acl_registration_ref_cnt.erase(ac_id_inf_id_inf_type);
1205 }
1206
1207 acl_ref_cnt[acl_id]--;
1208 if (acl_ref_cnt[acl_id] == 0) {
1209 remove_acl(acl_id);
1210 acl_ref_cnt.erase(acl_id);
1211 // Iterate acl_classifier_to_acl_id_map and delete classifier the key corresponding to acl_id
1212 std::map<acl_classifier_key, uint16_t>::iterator it;
1213 for (it=acl_classifier_to_acl_id_map.begin(); it!=acl_classifier_to_acl_id_map.end(); ++it) {
1214 if (it->second == acl_id) {
1215 OPENOLT_LOG(INFO, openolt_log_id, "cleared classifier key corresponding to acl_id = %d\n", acl_id);
1216 acl_classifier_to_acl_id_map.erase(it->first);
1217 break;
1218 }
1219 }
1220 }
1221
1222 clear_gem_port(gemport_id, intf_id);
1223
1224 return Status::OK;
1225}
1226
1227Status check_bal_ready() {
1228 bcmos_errno err;
1229 int maxTrials = 30;
1230 bcmolt_olt_cfg olt_cfg = { };
1231 bcmolt_olt_key olt_key = { };
1232
1233 BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
1234 BCMOLT_MSG_FIELD_GET(&olt_cfg, bal_state);
1235
1236 while (olt_cfg.data.bal_state != BCMOLT_BAL_STATE_BAL_AND_SWITCH_READY) {
1237 if (--maxTrials == 0)
1238 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check bal ready failed");
1239 sleep(5);
1240 #ifdef TEST_MODE
1241 // It is impossible to mock the setting of olt_cfg.data.bal_state because
1242 // the actual bcmolt_cfg_get passes the address of olt_cfg.hdr and we cannot
1243 // set the olt_cfg.data.bal_state. So a new stub function is created and address
1244 // of olt_cfg is passed. This is one-of case where we need to add test specific
1245 // code in production code.
1246 if (bcmolt_cfg_get__bal_state_stub(dev_id, &olt_cfg)) {
1247 #else
1248 if (bcmolt_cfg_get(dev_id, &olt_cfg.hdr)) {
1249 #endif
1250 continue;
1251 }
1252 else
1253 OPENOLT_LOG(INFO, openolt_log_id, "waiting for BAL ready ...\n");
1254 }
1255
1256 OPENOLT_LOG(INFO, openolt_log_id, "BAL is ready\n");
1257 return Status::OK;
1258}
1259
1260Status check_connection() {
1261 int maxTrials = 60;
1262 while (!bcmolt_api_conn_mgr_is_connected(dev_id)) {
1263 sleep(1);
1264 if (--maxTrials == 0)
1265 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check connection failed");
1266 else
1267 OPENOLT_LOG(INFO, openolt_log_id, "waiting for daemon connection ...\n");
1268 }
1269 OPENOLT_LOG(INFO, openolt_log_id, "daemon is connected\n");
1270 return Status::OK;
1271}
1272
Thiyagarajan Subramani03bc66f2020-04-01 15:58:53 +05301273std::string get_ip_address(const char* nw_intf){
1274 std::string ipAddress = "0.0.0.0";
1275 struct ifaddrs *interfaces = NULL;
1276 struct ifaddrs *temp_addr = NULL;
1277 int success = 0;
1278 /* retrieve the current interfaces - returns 0 on success */
1279 success = getifaddrs(&interfaces);
1280 if (success == 0) {
1281 /* Loop through linked list of interfaces */
1282 temp_addr = interfaces;
1283 while(temp_addr != NULL) {
1284 if(temp_addr->ifa_addr->sa_family == AF_INET) {
1285 /* Check if interface given present in OLT, if yes return its IP Address */
1286 if(strcmp(temp_addr->ifa_name, nw_intf) == 0){
1287 ipAddress=inet_ntoa(((struct sockaddr_in*)temp_addr->ifa_addr)->sin_addr);
1288 break;
1289 }
1290 }
1291 temp_addr = temp_addr->ifa_next;
1292 }
1293 }
1294 /* Free memory */
1295 freeifaddrs(interfaces);
1296 return ipAddress;
1297}
Jason Huang1d9cfce2020-05-20 22:58:47 +08001298
1299bcmos_errno getOnuMaxLogicalDistance(uint32_t intf_id, uint32_t *mld) {
1300 bcmos_errno err = BCM_ERR_OK;
1301 bcmolt_pon_distance pon_distance = {};
1302 bcmolt_pon_interface_cfg pon_cfg; /* declare main API struct */
1303 bcmolt_pon_interface_key key = {}; /* declare key */
1304
1305 key.pon_ni = intf_id;
1306
1307 if (!state.is_activated()) {
1308 OPENOLT_LOG(ERROR, openolt_log_id, "ONU maximum logical distance is not available since OLT is not activated yet\n");
1309 return BCM_ERR_STATE;
1310 }
1311
1312 /* Initialize the API struct. */
1313 BCMOLT_CFG_INIT(&pon_cfg, pon_interface, key);
1314 BCMOLT_FIELD_SET_PRESENT(&pon_distance, pon_distance, max_log_distance);
1315 BCMOLT_FIELD_SET(&pon_cfg.data, pon_interface_cfg_data, pon_distance, pon_distance);
1316 #ifdef TEST_MODE
1317 // It is impossible to mock the setting of pon_cfg.data.state because
1318 // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
1319 // set the pon_cfg.data.state. So a new stub function is created and address
1320 // of pon_cfg is passed. This is one-of case where we need to add test specific
1321 // code in production code.
1322 err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
1323 #else
1324 err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
1325 #endif
1326 if (err != BCM_ERR_OK) {
1327 OPENOLT_LOG(ERROR, openolt_log_id, "Failed to retrieve ONU maximum logical distance for PON %d, err = %s (%d)\n", intf_id, bcmos_strerror(err), err);
1328 return err;
1329 }
1330 *mld = pon_distance.max_log_distance;
1331
1332 return BCM_ERR_OK;
1333}