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