blob: 9bc765907a8e94f910b03bc4a86f557da2966440 [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
Orhan Kupusoglu1fd77072021-03-23 08:13:25 -070017#include <fstream>
18#include <sstream>
Girish Gowdraddf9a162020-01-27 12:56:27 +053019#include "core_utils.h"
20
Orhan Kupusoglu1fd77072021-03-23 08:13:25 -070021// save the TLS option
22static std::string tls_option_arg{};
23
Girish Gowdraddf9a162020-01-27 12:56:27 +053024std::string serial_number_to_str(bcmolt_serial_number* serial_number) {
25#define SERIAL_NUMBER_SIZE 12
26 char buff[SERIAL_NUMBER_SIZE+1];
27
28 sprintf(buff, "%c%c%c%c%1X%1X%1X%1X%1X%1X%1X%1X",
29 serial_number->vendor_id.arr[0],
30 serial_number->vendor_id.arr[1],
31 serial_number->vendor_id.arr[2],
32 serial_number->vendor_id.arr[3],
33 serial_number->vendor_specific.arr[0]>>4 & 0x0f,
34 serial_number->vendor_specific.arr[0] & 0x0f,
35 serial_number->vendor_specific.arr[1]>>4 & 0x0f,
36 serial_number->vendor_specific.arr[1] & 0x0f,
37 serial_number->vendor_specific.arr[2]>>4 & 0x0f,
38 serial_number->vendor_specific.arr[2] & 0x0f,
39 serial_number->vendor_specific.arr[3]>>4 & 0x0f,
40 serial_number->vendor_specific.arr[3] & 0x0f);
41
42 return buff;
43}
44
45std::string vendor_specific_to_str(char const * const vendor_specific) {
46 char buff[SERIAL_NUMBER_SIZE+1];
47
48 sprintf(buff, "%1X%1X%1X%1X%1X%1X%1X%1X",
49 vendor_specific[0]>>4 & 0x0f,
50 vendor_specific[0] & 0x0f,
51 vendor_specific[1]>>4 & 0x0f,
52 vendor_specific[1] & 0x0f,
53 vendor_specific[2]>>4 & 0x0f,
54 vendor_specific[2] & 0x0f,
55 vendor_specific[3]>>4 & 0x0f,
56 vendor_specific[3] & 0x0f);
57
58 return buff;
59}
60/**
61* Returns the default NNI (Upstream direction) or PON (Downstream direction) scheduler
62* Every NNI port and PON port have default scheduler.
63* The NNI0 default scheduler ID is 18432, and NNI1 is 18433 and so on.
64* Similarly, PON0 default scheduler ID is 16384. PON1 is 16385 and so on.
65*
66* @param intf_id NNI or PON interface ID
67* @param direction "upstream" or "downstream"
68*
69* @return default scheduler ID for the given interface.
70*/
71
72uint16_t get_dev_id(void) {
73 return dev_id;
74}
75
76int get_default_tm_sched_id(int intf_id, std::string direction) {
Girish Gowdrafc6c0bf2022-01-28 18:31:30 -080077 if (direction == upstream) {
Girish Gowdraddf9a162020-01-27 12:56:27 +053078 return tm_upstream_sched_id_start + intf_id;
Girish Gowdrafc6c0bf2022-01-28 18:31:30 -080079 } else if (direction == downstream) {
Girish Gowdraddf9a162020-01-27 12:56:27 +053080 return tm_downstream_sched_id_start + intf_id;
81 }
82 else {
83 OPENOLT_LOG(ERROR, openolt_log_id, "invalid direction - %s\n", direction.c_str());
84 return 0;
85 }
86}
87
88/**
89* Gets a unique tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
90* The tm_sched_id is locally cached in a map, so that it can rendered when necessary.
Burak Gurdag2f2618c2020-04-23 13:20:30 +000091* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem.
92* Note that tech_profile_id is used to differentiate service schedulers in downstream direction.
Girish Gowdraddf9a162020-01-27 12:56:27 +053093*
94* @param intf_id NNI or PON intf ID
95* @param onu_id ONU ID
96* @param uni_id UNI ID
97* @param gemport_id GEM Port ID
98* @param direction Upstream or downstream
Burak Gurdag2f2618c2020-04-23 13:20:30 +000099* @param tech_profile_id Technology Profile ID
Girish Gowdraddf9a162020-01-27 12:56:27 +0530100*
101* @return tm_sched_id
102*/
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000103uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
104 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530105 int sched_id = -1;
106
Girish Gowdra252f4972020-09-07 21:24:01 -0700107 bcmos_fastlock_lock(&tm_sched_bitset_lock);
108
Girish Gowdraddf9a162020-01-27 12:56:27 +0530109 std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
110 if (it != sched_map.end()) {
111 sched_id = it->second;
112 }
113 if (sched_id != -1) {
Girish Gowdra252f4972020-09-07 21:24:01 -0700114 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530115 return sched_id;
116 }
117
Girish Gowdraddf9a162020-01-27 12:56:27 +0530118 // Complexity of O(n). Is there better way that can avoid linear search?
119 for (sched_id = 0; sched_id < MAX_TM_SCHED_ID; sched_id++) {
120 if (tm_sched_bitset[sched_id] == 0) {
121 tm_sched_bitset[sched_id] = 1;
122 break;
123 }
124 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530125
126 if (sched_id < MAX_TM_SCHED_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530127 sched_map[key] = sched_id;
Girish Gowdra252f4972020-09-07 21:24:01 -0700128 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530129 return sched_id;
130 } else {
Girish Gowdra252f4972020-09-07 21:24:01 -0700131 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530132 return -1;
133 }
134}
135
136/**
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000137* 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 +0530138*
139* @param intf_id NNI or PON intf ID
140* @param onu_id ONU ID
141* @param uni_id UNI ID
142* @param gemport_id GEM Port ID
143* @param direction Upstream or downstream
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000144* @param tech_profile_id Technology Profile ID
Girish Gowdraddf9a162020-01-27 12:56:27 +0530145*/
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000146void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
147 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530148 std::map<sched_map_key_tuple, int>::const_iterator it;
Girish Gowdra252f4972020-09-07 21:24:01 -0700149 bcmos_fastlock_lock(&tm_sched_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530150 it = sched_map.find(key);
151 if (it != sched_map.end()) {
152 tm_sched_bitset[it->second] = 0;
153 sched_map.erase(it);
154 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700155 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530156}
157
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000158bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
159 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530160 std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
161 if (it != sched_map.end()) {
162 return true;
163 }
164 return false;
165}
166
167/**
168* Check whether given two tm qmp profiles are equal or not
169*
170* @param tmq_map_profileA <vector> TM QUEUE MAPPING PROFILE
171* @param tmq_map_profileB <vector> TM QUEUE MAPPING PROFILE
172*
173* @return boolean, true if given tmq_map_profiles are equal else false
174*/
175
176bool check_tm_qmp_equality(std::vector<uint32_t> tmq_map_profileA, std::vector<uint32_t> tmq_map_profileB) {
177 for (uint32_t i = 0; i < TMQ_MAP_PROFILE_SIZE; i++) {
178 if (tmq_map_profileA[i] != tmq_map_profileB[i]) {
179 return false;
180 }
181 }
182 return true;
183}
184
185/**
186* Modifies given queues_pbit_map to parsable format
187* e.g: Modifes "0b00000101" to "10100000"
188*
189* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
190* @param size Queue count
191*
192* @return string queues_pbit_map
193*/
194std::string* get_valid_queues_pbit_map(std::string *queues_pbit_map, uint32_t size) {
195 for(uint32_t i=0; i < size; i++) {
196 /* Deletes 2 characters from index number 0 */
197 queues_pbit_map[i].erase(0, 2);
198 std::reverse(queues_pbit_map[i].begin(), queues_pbit_map[i].end());
199 }
200 return queues_pbit_map;
201}
202
203/**
204* Creates TM QUEUE MAPPING PROFILE for given queues_pbit_map and queues_priority_q
205*
206* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
207* @param queues_priority_q PRIORITY_Q configured for each GEM in TECH PROFILE
208* @param size Queue count
209*
210* @return <vector> TM QUEUE MAPPING PROFILE
211*/
212std::vector<uint32_t> get_tmq_map_profile(std::string *queues_pbit_map, uint32_t *queues_priority_q, uint32_t size) {
213 std::vector<uint32_t> tmq_map_profile(8,0);
214
215 for(uint32_t i=0; i < size; i++) {
216 for (uint32_t j = 0; j < queues_pbit_map[i].size(); j++) {
217 if (queues_pbit_map[i][j]=='1') {
218 tmq_map_profile.at(j) = queue_id_list[queues_priority_q[i]];
219 }
220 }
221 }
222 return tmq_map_profile;
223}
224
225/**
226* Gets corresponding tm_qmp_id for a given tmq_map_profile
227*
228* @param <vector> TM QUEUE MAPPING PROFILE
229*
230* @return tm_qmp_id
231*/
232int get_tm_qmp_id(std::vector<uint32_t> tmq_map_profile) {
233 int tm_qmp_id = -1;
234
235 std::map<int, std::vector < uint32_t > >::const_iterator it = qmp_id_to_qmp_map.begin();
236 while(it != qmp_id_to_qmp_map.end()) {
237 if(check_tm_qmp_equality(tmq_map_profile, it->second)) {
238 tm_qmp_id = it->first;
239 break;
240 }
241 it++;
242 }
243 return tm_qmp_id;
244}
245
246/**
247* Updates sched_qmp_id_map with given sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id
248*
249* @param upstream/downstream sched_id
250* @param PON intf ID
251* @param onu_id ONU ID
252* @param uni_id UNI ID
253* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
254*/
255void update_sched_qmp_id_map(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
256 uint32_t uni_id, int tm_qmp_id) {
Girish Gowdra252f4972020-09-07 21:24:01 -0700257 bcmos_fastlock_lock(&tm_qmp_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530258 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
259 sched_qmp_id_map.insert(make_pair(key, tm_qmp_id));
Girish Gowdra252f4972020-09-07 21:24:01 -0700260 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530261}
262
263/**
264* Gets corresponding tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
265*
266* @param upstream/downstream sched_id
267* @param PON intf ID
268* @param onu_id ONU ID
269* @param uni_id UNI ID
270*
271* @return tm_qmp_id
272*/
273int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
274 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
275 int tm_qmp_id = -1;
276
277 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
278 if (it != sched_qmp_id_map.end()) {
279 tm_qmp_id = it->second;
280 }
281 return tm_qmp_id;
282}
283
284/**
285* Gets a unique tm_qmp_id for a given tmq_map_profile
286* The tm_qmp_id is locally cached in a map, so that it can be rendered when necessary.
287* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
288*
289* @param upstream/downstream sched_id
290* @param PON intf ID
291* @param onu_id ONU ID
292* @param uni_id UNI ID
293* @param <vector> TM QUEUE MAPPING PROFILE
294*
295* @return tm_qmp_id
296*/
297int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, \
298 std::vector<uint32_t> tmq_map_profile) {
299 int tm_qmp_id;
300
Girish Gowdra252f4972020-09-07 21:24:01 -0700301 bcmos_fastlock_lock(&tm_qmp_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530302 /* Complexity of O(n). Is there better way that can avoid linear search? */
303 for (tm_qmp_id = 0; tm_qmp_id < MAX_TM_QMP_ID; tm_qmp_id++) {
304 if (tm_qmp_bitset[tm_qmp_id] == 0) {
305 tm_qmp_bitset[tm_qmp_id] = 1;
306 break;
307 }
308 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530309
310 if (tm_qmp_id < MAX_TM_QMP_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530311 qmp_id_to_qmp_map.insert(make_pair(tm_qmp_id, tmq_map_profile));
Girish Gowdra252f4972020-09-07 21:24:01 -0700312 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530313 update_sched_qmp_id_map(sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id);
314 return tm_qmp_id;
315 } else {
Girish Gowdra252f4972020-09-07 21:24:01 -0700316 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530317 return -1;
318 }
319}
320
321/**
322* Free tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
323*
324* @param upstream/downstream sched_id
325* @param PON intf ID
326* @param onu_id ONU ID
327* @param uni_id UNI ID
328* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
329*
330* @return boolean, true if no more reference for TM QMP else false
331*/
332bool free_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
333 uint32_t uni_id, int tm_qmp_id) {
334 bool result;
335 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
336 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
Girish Gowdra252f4972020-09-07 21:24:01 -0700337 bcmos_fastlock_lock(&tm_qmp_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530338 if (it != sched_qmp_id_map.end()) {
339 sched_qmp_id_map.erase(it);
340 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530341
342 uint32_t tm_qmp_ref_count = 0;
343 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it2 = sched_qmp_id_map.begin();
344 while(it2 != sched_qmp_id_map.end()) {
345 if(it2->second == tm_qmp_id) {
346 tm_qmp_ref_count++;
347 }
348 it2++;
349 }
350
351 if (tm_qmp_ref_count == 0) {
352 std::map<int, std::vector < uint32_t > >::const_iterator it3 = qmp_id_to_qmp_map.find(tm_qmp_id);
353 if (it3 != qmp_id_to_qmp_map.end()) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530354 tm_qmp_bitset[tm_qmp_id] = 0;
355 qmp_id_to_qmp_map.erase(it3);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530356 OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So clearing it\n", \
357 tm_qmp_id, tm_qmp_ref_count);
358 result = true;
359 }
360 } else {
361 OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So not clearing it\n", \
362 tm_qmp_id, tm_qmp_ref_count);
363 result = false;
364 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700365 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
366
Girish Gowdraddf9a162020-01-27 12:56:27 +0530367 return result;
368}
369
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530370/* ACL ID is a shared resource, caller of this function has to ensure atomicity using locks
371 Gets free ACL ID if available, else -1. */
Girish Gowdraddf9a162020-01-27 12:56:27 +0530372int get_acl_id() {
373 int acl_id;
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530374
Girish Gowdra252f4972020-09-07 21:24:01 -0700375 bcmos_fastlock_lock(&acl_id_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530376 /* Complexity of O(n). Is there better way that can avoid linear search? */
377 for (acl_id = 0; acl_id < MAX_ACL_ID; acl_id++) {
378 if (acl_id_bitset[acl_id] == 0) {
379 acl_id_bitset[acl_id] = 1;
380 break;
381 }
382 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700383 bcmos_fastlock_unlock(&acl_id_bitset_lock, 0);
384
Girish Gowdraddf9a162020-01-27 12:56:27 +0530385 if (acl_id < MAX_ACL_ID) {
386 return acl_id ;
387 } else {
388 return -1;
389 }
390}
391
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530392/* ACL ID is a shared resource, caller of this function has to ensure atomicity using locks
393 Frees up the ACL ID. */
Girish Gowdraddf9a162020-01-27 12:56:27 +0530394void free_acl_id (int acl_id) {
Girish Gowdra252f4972020-09-07 21:24:01 -0700395 bcmos_fastlock_lock(&acl_id_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530396 if (acl_id < MAX_ACL_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530397 acl_id_bitset[acl_id] = 0;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530398 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700399 bcmos_fastlock_unlock(&acl_id_bitset_lock, 0);
400}
401
402/* Gets a free Flow ID if available, else INVALID_FLOW_ID */
403uint16_t get_flow_id() {
404 uint16_t flow_id;
405
406 bcmos_fastlock_lock(&flow_id_bitset_lock);
407 /* Complexity of O(n). Is there better way that can avoid linear search? */
408 // start flow_id from 1 as 0 is invalid
409 for (flow_id = FLOW_ID_START; flow_id <= FLOW_ID_END; flow_id++) {
410 if (flow_id_bitset[flow_id] == 0) {
411 flow_id_bitset[flow_id] = 1;
412 break;
413 }
414 }
415 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
416
417 if (flow_id <= MAX_FLOW_ID) {
418 return flow_id ;
419 } else {
420 return INVALID_FLOW_ID;
421 }
422}
423
424/* Gets requested number of Flow IDs.
425 'num_of_flow_ids' is number of flow_ids requested. This cannot be more than NUMBER_OF_PBITS
426 'flow_ids' is pointer to array of size NUMBER_OF_PBITS
427 If the operation is successful, returns true else false
428 The operation is successful if we can allocate fully the number of flow_ids requested.
429 */
430bool get_flow_ids(int num_of_flow_ids, uint16_t *flow_ids) {
431 if (num_of_flow_ids > NUMBER_OF_PBITS) {
432 OPENOLT_LOG(ERROR, openolt_log_id, "requested number of flow_ids is more than 8\n");
433 return false;
434 }
435 int cnt = 0;
436
437 bcmos_fastlock_lock(&flow_id_bitset_lock);
438 /* Complexity of O(n). Is there better way that can avoid linear search? */
439 // start flow_id from 1 as 0 is invalid
440 for (uint16_t flow_id = FLOW_ID_START; flow_id <= FLOW_ID_END && cnt < num_of_flow_ids; flow_id++) {
441 if (flow_id_bitset[flow_id] == 0) {
442 flow_id_bitset[flow_id] = 1;
443 flow_ids[cnt] = flow_id;
444 cnt++;
445 }
446 }
447 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
448 // If we could not allocate the requested number of flow_ids free the allocated flow_ids
449 // and return false
450 if (cnt != num_of_flow_ids) {
451 OPENOLT_LOG(ERROR, openolt_log_id, "could not allocated the rquested number of flows ids. requested=%d, allocated=%d", num_of_flow_ids, cnt);
452 if (cnt > 0) {
453 for(int i=0; i < cnt; i++) {
454 free_flow_id(flow_ids[i]);
455 }
456 }
457 return false;
458 }
459 return true;
460}
461
462/* Frees up the FLOW ID. */
463void free_flow_id (uint16_t flow_id) {
464 bcmos_fastlock_lock(&flow_id_bitset_lock);
465 if (flow_id <= MAX_FLOW_ID) {
466 flow_id_bitset[flow_id] = 0;
467 }
468 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
469}
470
471void free_flow_ids(uint8_t num_flows, uint16_t *flow_ids) {
472 for (uint8_t i = 0; i < num_flows; i++) {
473 bcmos_fastlock_lock(&flow_id_bitset_lock);
474 if (flow_ids[i] <= MAX_FLOW_ID) {
475 flow_id_bitset[flow_ids[i]] = 0;
476 }
477 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
478 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530479}
480
481/**
482* Returns qos type as string
483*
484* @param qos_type bcmolt_egress_qos_type enum
485*/
486std::string get_qos_type_as_string(bcmolt_egress_qos_type qos_type) {
487 switch (qos_type)
488 {
489 case BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE: return "FIXED_QUEUE";
490 case BCMOLT_EGRESS_QOS_TYPE_TC_TO_QUEUE: return "TC_TO_QUEUE";
491 case BCMOLT_EGRESS_QOS_TYPE_PBIT_TO_TC: return "PBIT_TO_TC";
492 case BCMOLT_EGRESS_QOS_TYPE_NONE: return "NONE";
493 case BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE: return "PRIORITY_TO_QUEUE";
494 default: OPENOLT_LOG(ERROR, openolt_log_id, "qos-type-not-supported %d\n", qos_type);
495 return "qos-type-not-supported";
496 }
497}
498
499/**
500* Gets/Updates qos type for given pon_intf_id, onu_id, uni_id
501*
502* @param PON intf ID
503* @param onu_id ONU ID
504* @param uni_id UNI ID
505* @param queue_size TrafficQueues Size
506*
507* @return qos_type
508*/
509bcmolt_egress_qos_type get_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, uint32_t queue_size) {
510 qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
511 bcmolt_egress_qos_type egress_qos_type = BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
512 std::string qos_string;
513
514 std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
515 if (it != qos_type_map.end()) {
516 egress_qos_type = it->second;
517 qos_string = get_qos_type_as_string(egress_qos_type);
518 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", \
519 pon_intf_id, onu_id, uni_id, qos_string.c_str());
520 }
521 else {
522 /* QOS Type has been pre-defined as Fixed Queue but it will be updated based on number of GEMPORTS
523 associated for a given subscriber. If GEM count = 1 for a given subscriber, qos_type will be Fixed Queue
524 else Priority to Queue */
525 egress_qos_type = (queue_size > 1) ? \
526 BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE : BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
527 bcmos_fastlock_lock(&data_lock);
528 qos_type_map.insert(make_pair(key, egress_qos_type));
529 bcmos_fastlock_unlock(&data_lock, 0);
530 qos_string = get_qos_type_as_string(egress_qos_type);
531 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", \
532 pon_intf_id, onu_id, uni_id, qos_string.c_str());
533 }
534 return egress_qos_type;
535}
536
537/**
538* Clears qos type for given pon_intf_id, onu_id, uni_id
539*
540* @param PON intf ID
541* @param onu_id ONU ID
542* @param uni_id UNI ID
543*/
544void clear_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
545 qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
546 std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
547 bcmos_fastlock_lock(&data_lock);
548 if (it != qos_type_map.end()) {
549 qos_type_map.erase(it);
550 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", \
551 pon_intf_id, onu_id, uni_id);
552 }
553 bcmos_fastlock_unlock(&data_lock, 0);
554}
555
556/**
557* Returns Scheduler/Queue direction as string
558*
559* @param direction as specified in tech_profile.proto
560*/
561std::string GetDirection(int direction) {
562 switch (direction)
563 {
564 case tech_profile::Direction::UPSTREAM: return upstream;
565 case tech_profile::Direction::DOWNSTREAM: return downstream;
566 default: OPENOLT_LOG(ERROR, openolt_log_id, "direction-not-supported %d\n", direction);
567 return "direction-not-supported";
568 }
569}
570
571// This method handles waiting for AllocObject configuration.
572// Returns error if the AllocObject is not in the appropriate state based on action requested.
573bcmos_errno wait_for_alloc_action(uint32_t intf_id, uint32_t alloc_id, AllocCfgAction action) {
574 Queue<alloc_cfg_complete_result> cfg_result;
575 alloc_cfg_compltd_key k(intf_id, alloc_id);
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +0530576 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530577 alloc_cfg_compltd_map[k] = &cfg_result;
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +0530578 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530579 bcmos_errno err = BCM_ERR_OK;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530580
581 // Try to pop the result from BAL with a timeout of ALLOC_CFG_COMPLETE_WAIT_TIMEOUT ms
582 std::pair<alloc_cfg_complete_result, bool> result = cfg_result.pop(ALLOC_CFG_COMPLETE_WAIT_TIMEOUT);
583 if (result.second == false) {
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530584 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for alloc cfg complete indication intf_id %d, alloc_id %d, action = %d\n",
585 intf_id, alloc_id, action);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530586 // Invalidate the queue pointer.
587 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
588 alloc_cfg_compltd_map[k] = NULL;
589 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
590 err = BCM_ERR_INTERNAL;
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530591 // If the Alloc object is already in the right state after the performed operation, return OK.
592 bcmolt_activation_state state;
593 err = get_alloc_obj_state(intf_id, alloc_id, &state);
594 if (err) {
595 OPENOLT_LOG(ERROR, openolt_log_id, "error fetching alloc obj state intf_id = %d, alloc_id %d, action = %d, err = %d\n",
596 intf_id, alloc_id, action, err);
597 return err;
598 }
599 if ((state == BCMOLT_ACTIVATION_STATE_NOT_CONFIGURED && action == ALLOC_OBJECT_DELETE) ||
600 (state == BCMOLT_ACTIVATION_STATE_ACTIVE && action == ALLOC_OBJECT_CREATE)) {
601 OPENOLT_LOG(WARNING, openolt_log_id, "operation timed out, but the alloc object is the right state intf_id = %d, gem_port_id %d, action = %d\n",
602 intf_id, alloc_id, action);
603 return BCM_ERR_OK;
604 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530605 }
606 else if (result.first.status == ALLOC_CFG_STATUS_FAIL) {
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530607 OPENOLT_LOG(ERROR, openolt_log_id, "error processing alloc cfg request intf_id %d, alloc_id %d, action = %d\n",
608 intf_id, alloc_id, action);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530609 err = BCM_ERR_INTERNAL;
610 }
611
612 if (err == BCM_ERR_OK) {
613 if (action == ALLOC_OBJECT_CREATE) {
614 if (result.first.state != ALLOC_OBJECT_STATE_ACTIVE) {
615 OPENOLT_LOG(ERROR, openolt_log_id, "alloc object not in active state intf_id %d, alloc_id %d alloc_obj_state %d\n",
616 intf_id, alloc_id, result.first.state);
617 err = BCM_ERR_INTERNAL;
618 } else {
619 OPENOLT_LOG(INFO, openolt_log_id, "Create upstream bandwidth allocation success, intf_id %d, alloc_id %d\n",
620 intf_id, alloc_id);
621 }
622 } else { // ALLOC_OBJECT_DELETE
623 if (result.first.state != ALLOC_OBJECT_STATE_NOT_CONFIGURED) {
624 OPENOLT_LOG(ERROR, openolt_log_id, "alloc object is not reset intf_id %d, alloc_id %d alloc_obj_state %d\n",
625 intf_id, alloc_id, result.first.state);
626 err = BCM_ERR_INTERNAL;
627 } else {
628 OPENOLT_LOG(INFO, openolt_log_id, "Remove alloc object success, intf_id %d, alloc_id %d\n",
629 intf_id, alloc_id);
630 }
631 }
632 }
633
634 // Remove entry from map
635 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
636 alloc_cfg_compltd_map.erase(k);
637 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
Girish Gowdra7a79dae2020-02-10 18:22:11 +0530638 return err;
639}
640
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +0530641// This method handles waiting for GemObject configuration.
642// Returns error if the GemObject is not in the appropriate state based on action requested.
643bcmos_errno wait_for_gem_action(uint32_t intf_id, uint32_t gem_port_id, GemCfgAction action) {
644 Queue<gem_cfg_complete_result> cfg_result;
645 gem_cfg_compltd_key k(intf_id, gem_port_id);
646 bcmos_fastlock_lock(&gem_cfg_wait_lock);
647 gem_cfg_compltd_map[k] = &cfg_result;
648 bcmos_fastlock_unlock(&gem_cfg_wait_lock, 0);
649 bcmos_errno err = BCM_ERR_OK;
650
651 // Try to pop the result from BAL with a timeout of GEM_CFG_COMPLETE_WAIT_TIMEOUT ms
652 std::pair<gem_cfg_complete_result, bool> result = cfg_result.pop(GEM_CFG_COMPLETE_WAIT_TIMEOUT);
653 if (result.second == false) {
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530654 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for gem cfg complete indication intf_id %d, gem_port_id %d, action = %d\n",
655 intf_id, gem_port_id, action);
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +0530656 // Invalidate the queue pointer.
657 bcmos_fastlock_lock(&gem_cfg_wait_lock);
658 gem_cfg_compltd_map[k] = NULL;
659 bcmos_fastlock_unlock(&gem_cfg_wait_lock, 0);
660 err = BCM_ERR_INTERNAL;
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530661 // If the GEM object is already in the right state after the performed operation, return OK.
662 bcmolt_activation_state state;
663 err = get_gem_obj_state(intf_id, gem_port_id, &state);
664 if (err) {
665 OPENOLT_LOG(ERROR, openolt_log_id, "error fetching gem obj state intf_id = %d, gem_port_id %d, action = %d, err = %d\n",
666 intf_id, gem_port_id, action, err);
667 return err;
668 }
669 if ((state == BCMOLT_ACTIVATION_STATE_NOT_CONFIGURED && action == GEM_OBJECT_DELETE) ||
670 (state == BCMOLT_ACTIVATION_STATE_ACTIVE && action == GEM_OBJECT_CREATE)) {
671 OPENOLT_LOG(WARNING, openolt_log_id, "operation timed out, but the gem object is the right state intf_id = %d, gem_port_id %d, action = %d\n",
672 intf_id, gem_port_id, action);
673 return BCM_ERR_OK;
674 }
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +0530675 }
676 else if (result.first.status == GEM_CFG_STATUS_FAIL) {
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530677 OPENOLT_LOG(ERROR, openolt_log_id, "error processing gem cfg request intf_id %d, gem_port_id %d, action = %d\n",
678 intf_id, gem_port_id, action);
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +0530679 err = BCM_ERR_INTERNAL;
680 }
681
682 if (err == BCM_ERR_OK) {
683 if (action == GEM_OBJECT_CREATE) {
684 if (result.first.state != GEM_OBJECT_STATE_ACTIVE) {
685 OPENOLT_LOG(ERROR, openolt_log_id, "gem object not in active state intf_id %d, gem_port_id %d gem_obj_state %d\n",
686 intf_id, gem_port_id, result.first.state);
687 err = BCM_ERR_INTERNAL;
688 } else {
689 OPENOLT_LOG(INFO, openolt_log_id, "Create itupon gem object success, intf_id %d, gem_port_id %d\n",
690 intf_id, gem_port_id);
691 }
692 } else if (action == GEM_OBJECT_ENCRYPT) {
693 if (result.first.state != GEM_OBJECT_STATE_ACTIVE) {
694 OPENOLT_LOG(ERROR, openolt_log_id, "gem object not in active state intf_id %d, gem_port_id %d gem_obj_state %d\n",
695 intf_id, gem_port_id, result.first.state);
696 err = BCM_ERR_INTERNAL;
697 } else {
698 OPENOLT_LOG(INFO, openolt_log_id, "Enable itupon gem object encryption success, intf_id %d, gem_port_id %d\n",
699 intf_id, gem_port_id);
700 }
701 } else { // GEM_OBJECT_DELETE
702 if (result.first.state != GEM_OBJECT_STATE_NOT_CONFIGURED) {
703 OPENOLT_LOG(ERROR, openolt_log_id, "gem object is not reset intf_id %d, gem_port_id %d gem_obj_state %d\n",
704 intf_id, gem_port_id, result.first.state);
705 err = BCM_ERR_INTERNAL;
706 } else {
707 OPENOLT_LOG(INFO, openolt_log_id, "Remove itupon gem object success, intf_id %d, gem_port_id %d\n",
708 intf_id, gem_port_id);
709 }
710 }
711 }
712
713 // Remove entry from map
714 bcmos_fastlock_lock(&gem_cfg_wait_lock);
715 gem_cfg_compltd_map.erase(k);
716 bcmos_fastlock_unlock(&gem_cfg_wait_lock, 0);
717 return err;
718}
719
Girish Gowdra7a79dae2020-02-10 18:22:11 +0530720// This method handles waiting for OnuDeactivate Completed Indication
721bcmos_errno wait_for_onu_deactivate_complete(uint32_t intf_id, uint32_t onu_id) {
722 Queue<onu_deactivate_complete_result> deact_result;
723 onu_deact_compltd_key k(intf_id, onu_id);
724 onu_deact_compltd_map[k] = &deact_result;
725 bcmos_errno err = BCM_ERR_OK;
726
727 // Try to pop the result from BAL with a timeout of ONU_DEACTIVATE_COMPLETE_WAIT_TIMEOUT ms
728 std::pair<onu_deactivate_complete_result, bool> result = deact_result.pop(ONU_DEACTIVATE_COMPLETE_WAIT_TIMEOUT);
729 if (result.second == false) {
730 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for onu deactivate complete indication intf_id %d, onu_id %d\n",
731 intf_id, onu_id);
732 // Invalidate the queue pointer.
733 bcmos_fastlock_lock(&onu_deactivate_wait_lock);
734 onu_deact_compltd_map[k] = NULL;
735 bcmos_fastlock_unlock(&onu_deactivate_wait_lock, 0);
736 err = BCM_ERR_INTERNAL;
737 }
738 else if (result.first.result == BCMOLT_RESULT_FAIL) {
739 OPENOLT_LOG(ERROR, openolt_log_id, "error processing onu deactivate request intf_id %d, onu_id %d, fail_reason %d\n",
740 intf_id, onu_id, result.first.reason);
741 err = BCM_ERR_INTERNAL;
742 } else if (result.first.result == BCMOLT_RESULT_SUCCESS) {
743 OPENOLT_LOG(INFO, openolt_log_id, "success processing onu deactivate request intf_id %d, onu_id %d\n",
744 intf_id, onu_id);
745 }
746
747 // Remove entry from map
748 bcmos_fastlock_lock(&onu_deactivate_wait_lock);
749 onu_deact_compltd_map.erase(k);
750 bcmos_fastlock_unlock(&onu_deactivate_wait_lock, 0);
751
Girish Gowdraddf9a162020-01-27 12:56:27 +0530752 return err;
753}
754
755char* openolt_read_sysinfo(const char* field_name, char* field_val)
756{
757 FILE *fp;
758 /* Prepare the command*/
759 char command[150];
760
761 snprintf(command, sizeof command, "bash -l -c \"onlpdump -s\" | perl -ne 'print $1 if /%s: (\\S+)/'", field_name);
762 /* Open the command for reading. */
763 fp = popen(command, "r");
764 if (fp == NULL) {
765 /*The client has to check for a Null field value in this case*/
766 OPENOLT_LOG(INFO, openolt_log_id, "Failed to query the %s\n", field_name);
767 return field_val;
768 }
769
770 /*Read the field value*/
771 if (fp) {
772 uint8_t ret;
773 ret = fread(field_val, OPENOLT_FIELD_LEN, 1, fp);
774 if (ret >= OPENOLT_FIELD_LEN)
775 OPENOLT_LOG(INFO, openolt_log_id, "Read data length %u\n", ret);
776 pclose(fp);
777 }
778 return field_val;
779}
780
Elia Battiston869a5de2022-02-08 11:40:58 +0100781Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state, uint32_t speed)
Girish Gowdraddf9a162020-01-27 12:56:27 +0530782{
Girish Gowdra252f4972020-09-07 21:24:01 -0700783 ::openolt::Indication ind;
784 ::openolt::IntfOperIndication* intf_oper_ind = new ::openolt::IntfOperIndication;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530785
786 intf_oper_ind->set_type(type);
787 intf_oper_ind->set_intf_id(intf_id);
788 intf_oper_ind->set_oper_state(state);
Elia Battiston869a5de2022-02-08 11:40:58 +0100789 intf_oper_ind->set_speed(speed);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530790 ind.set_allocated_intf_oper_ind(intf_oper_ind);
791 oltIndQ.push(ind);
792 return Status::OK;
793}
794
795#define CLI_HOST_PROMPT_FORMAT "BCM.%u> "
796
797/* Build CLI prompt */
798void openolt_cli_get_prompt_cb(bcmcli_session *session, char *buf, uint32_t max_len)
799{
800 snprintf(buf, max_len, CLI_HOST_PROMPT_FORMAT, dev_id);
801}
802
803int _bal_apiend_cli_thread_handler(long data)
804{
805 char init_string[]="\n";
806 bcmcli_session *sess = current_session;
807 bcmos_task_parm bal_cli_task_p_dummy;
808
809 /* Switch to interactive mode if not stopped in the init script */
810 if (!bcmcli_is_stopped(sess)) {
811 /* Force a CLI command prompt
812 * The string passed into the parse function
813 * must be modifiable, so a string constant like
814 * bcmcli_parse(current_session, "\n") will not
815 * work.
816 */
817 bcmcli_parse(sess, init_string);
818
819 /* Process user input until EOF or quit command */
820 bcmcli_driver(sess);
821 }
822 OPENOLT_LOG(INFO, openolt_log_id, "BAL API End CLI terminated\n");
823
824 /* Cleanup */
825 bcmcli_session_close(current_session);
826 bcmcli_token_destroy(NULL);
827 return 0;
828}
829
830/* Init API CLI commands for the current device */
831bcmos_errno bcm_openolt_api_cli_init(bcmcli_entry *parent_dir, bcmcli_session *session)
832{
833 bcmos_errno rc;
834
835 api_parent_dir = parent_dir;
836
837 rc = bcm_api_cli_set_commands(session);
838
839#ifdef BCM_SUBSYSTEM_HOST
840 /* Subscribe for device change indication */
841 rc = rc ? rc : bcmolt_olt_sel_ind_register(_api_cli_olt_change_ind);
842#endif
843
844 return rc;
845}
846
847bcmos_errno bcm_cli_quit(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
848{
849 bcmcli_stop(session);
850 bcmcli_session_print(session, "CLI terminated by 'Quit' command\n");
851 status_bcm_cli_quit = BCMOS_TRUE;
852
853 return BCM_ERR_OK;
854}
855
856int get_status_bcm_cli_quit(void) {
857 return status_bcm_cli_quit;
858}
859
860bcmos_errno bcmolt_apiend_cli_init() {
861 bcmos_errno ret;
862 bcmos_task_parm bal_cli_task_p = {};
863 bcmos_task_parm bal_cli_task_p_dummy;
864
865 /** before creating the task, check if it is already created by the other half of BAL i.e. Core side */
866 if (BCM_ERR_OK != bcmos_task_query(&bal_cli_thread, &bal_cli_task_p_dummy)) {
867 /* Create BAL CLI thread */
868 bal_cli_task_p.name = bal_cli_thread_name;
869 bal_cli_task_p.handler = _bal_apiend_cli_thread_handler;
870 bal_cli_task_p.priority = TASK_PRIORITY_CLI;
871
872 ret = bcmos_task_create(&bal_cli_thread, &bal_cli_task_p);
873 if (BCM_ERR_OK != ret) {
874 bcmos_printf("Couldn't create BAL API end CLI thread\n");
875 return ret;
876 }
877 }
878}
879
Girish Gowdra72cbee92021-11-05 15:16:18 -0700880bcmos_errno get_onu_state(bcmolt_interface pon_ni, int onu_id, bcmolt_onu_state *onu_state) {
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530881 bcmos_errno err;
882 bcmolt_onu_cfg onu_cfg;
883 bcmolt_onu_key onu_key;
884 onu_key.pon_ni = pon_ni;
885 onu_key.onu_id = onu_id;
886
887 BCMOLT_CFG_INIT(&onu_cfg, onu, onu_key);
Girish Gowdra72cbee92021-11-05 15:16:18 -0700888 BCMOLT_MSG_FIELD_GET(&onu_cfg, onu_state);
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530889 err = bcmolt_cfg_get(dev_id, &onu_cfg.hdr);
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530890 *onu_state = onu_cfg.data.onu_state;
891 return err;
892}
893
nikesh.krishnan331d38c2023-04-06 03:24:53 +0530894bcmos_errno get_gpon_onu_info(bcmolt_interface pon_ni, int onu_id, bcmolt_onu_state *onu_state, bcmolt_status *losi, bcmolt_status *lofi, bcmolt_status *loami)
895{
896
897 bcmos_errno err;
898 bcmolt_onu_cfg onu_cfg;
899 bcmolt_itu_onu_params itu = {};
900 bcmolt_gpon_onu_alarm_state alarm_state = {};
901 bcmolt_gpon_onu_params gpon = {};
902
903 bcmolt_onu_cfg onu_cfg_itu;
904 bcmolt_onu_key onu_key;
905 onu_key.pon_ni = pon_ni;
906 onu_key.onu_id = onu_id;
907
908 BCMOLT_CFG_INIT(&onu_cfg, onu, onu_key);
909 BCMOLT_FIELD_SET_PRESENT(&onu_cfg.data, onu_cfg_data, onu_state);
910
911 BCMOLT_FIELD_SET_PRESENT(&onu_cfg.data, onu_cfg_data, itu);
912
913 BCMOLT_FIELD_SET_PRESENT(&itu, itu_onu_params, gpon);
914 BCMOLT_FIELD_SET_PRESENT(&gpon, gpon_onu_params, alarm_state);
915
916 BCMOLT_FIELD_SET_PRESENT(&alarm_state, gpon_onu_alarm_state, losi);
917 BCMOLT_FIELD_SET_PRESENT(&alarm_state, gpon_onu_alarm_state, lofi);
918 BCMOLT_FIELD_SET_PRESENT(&alarm_state, gpon_onu_alarm_state, loami);
919
920 BCMOLT_FIELD_SET(&gpon, gpon_onu_params, alarm_state, alarm_state);
921
922 BCMOLT_FIELD_SET(&itu, itu_onu_params, gpon, gpon);
923
924 BCMOLT_FIELD_SET(&onu_cfg.data, onu_cfg_data, itu, itu);
925
926 err = bcmolt_cfg_get(dev_id, &onu_cfg.hdr);
927
928 *onu_state = onu_cfg.data.onu_state;
929 // fetch onu itu
930 *losi = onu_cfg.data.itu.gpon.alarm_state.losi;
931
932 *lofi = onu_cfg.data.itu.gpon.alarm_state.lofi;
933
934 *loami = onu_cfg.data.itu.gpon.alarm_state.loami;
935
936 return err;
937}
938
Girish Gowdracdd5e5f2021-12-05 16:48:08 +0530939bcmos_errno get_gem_obj_state(bcmolt_interface pon_ni, bcmolt_gem_port_id id, bcmolt_activation_state *state) {
940 bcmos_errno err;
941 bcmolt_itupon_gem_cfg cfg;
942 bcmolt_itupon_gem_key key;
943 key.pon_ni = pon_ni;
944 key.gem_port_id = id;
945
946 BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
947 BCMOLT_MSG_FIELD_GET(&cfg, state);
948 err = bcmolt_cfg_get(dev_id, &cfg.hdr);
949 *state = cfg.data.state;
950 return err;
951}
952
953bcmos_errno get_alloc_obj_state(bcmolt_interface pon_ni, bcmolt_alloc_id id, bcmolt_activation_state *state) {
954 bcmos_errno err;
955 bcmolt_itupon_alloc_cfg cfg;
956 bcmolt_itupon_alloc_key key;
957 key.pon_ni = pon_ni;
958 key.alloc_id = id;
959
960 BCMOLT_CFG_INIT(&cfg, itupon_alloc, key);
961 BCMOLT_MSG_FIELD_GET(&cfg, state);
962 err = bcmolt_cfg_get(dev_id, &cfg.hdr);
963 *state = cfg.data.state;
964 return err;
965}
966
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530967bcmos_errno get_pon_interface_status(bcmolt_interface pon_ni, bcmolt_interface_state *state, bcmolt_status *los_status) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530968 bcmos_errno err;
969 bcmolt_pon_interface_key pon_key;
970 bcmolt_pon_interface_cfg pon_cfg;
971 pon_key.pon_ni = pon_ni;
972
973 BCMOLT_CFG_INIT(&pon_cfg, pon_interface, pon_key);
974 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, state);
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530975 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, los_status);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530976 #ifdef TEST_MODE
977 // It is impossible to mock the setting of pon_cfg.data.state because
978 // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
979 // set the pon_cfg.data.state. So a new stub function is created and address
980 // of pon_cfg is passed. This is one-of case where we need to add test specific
981 // code in production code.
982 err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
983 #else
984 err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
985 #endif
986 *state = pon_cfg.data.state;
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530987 *los_status = pon_cfg.data.los_status;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530988 return err;
989}
990
991/* Same as bcmolt_cfg_get but with added logic of retrying the API
992 in case of some specific failures like timeout or object not yet ready
993*/
994bcmos_errno bcmolt_cfg_get_mult_retry(bcmolt_oltid olt, bcmolt_cfg *cfg) {
995 bcmos_errno err;
996 uint32_t current_try = 0;
997
998 while (current_try < MAX_BAL_API_RETRY_COUNT) {
999 err = bcmolt_cfg_get(olt, cfg);
1000 current_try++;
1001
1002 if (err == BCM_ERR_STATE || err == BCM_ERR_TIMEOUT) {
1003 OPENOLT_LOG(WARNING, openolt_log_id, "bcmolt_cfg_get: err = %s\n", bcmos_strerror(err));
1004 bcmos_usleep(BAL_API_RETRY_TIME_IN_USECS);
1005 continue;
1006 }
1007 else {
1008 break;
1009 }
1010 }
1011
1012 if (err != BCM_ERR_OK) {
1013 OPENOLT_LOG(ERROR, openolt_log_id, "bcmolt_cfg_get tried (%d) times with retry time(%d usecs) err = %s\n",
1014 current_try,
1015 BAL_API_RETRY_TIME_IN_USECS,
1016 bcmos_strerror(err));
1017 }
1018 return err;
1019}
1020
1021
1022unsigned NumNniIf_() {return num_of_nni_ports;}
1023unsigned NumPonIf_() {return num_of_pon_ports;}
1024
1025bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state) {
1026 bcmos_errno err;
1027 bcmolt_nni_interface_key nni_key;
1028 bcmolt_nni_interface_cfg nni_cfg;
1029 nni_key.id = id;
1030
1031 BCMOLT_CFG_INIT(&nni_cfg, nni_interface, nni_key);
1032 BCMOLT_FIELD_SET_PRESENT(&nni_cfg.data, nni_interface_cfg_data, state);
1033 #ifdef TEST_MODE
1034 // It is impossible to mock the setting of nni_cfg.data.state because
1035 // the actual bcmolt_cfg_get passes the address of nni_cfg.hdr and we cannot
1036 // set the nni_cfg.data.state. So a new stub function is created and address
1037 // of nni_cfg is passed. This is one-of case where we need to add test specific
1038 // code in production code.
1039 err = bcmolt_cfg_get__nni_intf_stub(dev_id, &nni_cfg);
1040 #else
1041 err = bcmolt_cfg_get(dev_id, &nni_cfg.hdr);
1042 #endif
1043 *state = nni_cfg.data.state;
1044 return err;
1045}
1046
Elia Battiston869a5de2022-02-08 11:40:58 +01001047bcmos_errno get_nni_interface_speed(bcmolt_interface id, uint32_t *speed)
1048{
1049 bcmos_errno err;
1050 bcmolt_nni_interface_key nni_key;
1051 bcmolt_nni_interface_cfg nni_cfg;
1052 nni_key.id = id;
1053
1054 BCMOLT_CFG_INIT(&nni_cfg, nni_interface, nni_key);
1055 BCMOLT_FIELD_SET_PRESENT(&nni_cfg.data, nni_interface_cfg_data, speed);
1056 err = bcmolt_cfg_get(dev_id, &nni_cfg.hdr);
1057 *speed = nni_cfg.data.speed;
1058 return err;
1059}
1060
Thiyagarajan Subramani19168f52021-05-25 23:26:41 +05301061Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t uni_id, int32_t gemport_id, std::string board_technology) {
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301062 gemport_status_map_key_tuple gem_status_key(intf_id, onu_id, uni_id, gemport_id);
1063
1064 bcmos_fastlock_lock(&data_lock);
1065 std::map<gemport_status_map_key_tuple, bool>::const_iterator it = gemport_status_map.find(gem_status_key);
1066 if (it != gemport_status_map.end()) {
1067 if (it->second) {
1068 bcmos_fastlock_unlock(&data_lock, 0);
1069 OPENOLT_LOG(INFO, openolt_log_id, "gem port already installed = %d\n", gemport_id);
1070 return Status::OK;
1071 }
1072 }
1073 bcmos_fastlock_unlock(&data_lock, 0);
1074
Girish Gowdraddf9a162020-01-27 12:56:27 +05301075 bcmos_errno err;
1076 bcmolt_itupon_gem_cfg cfg; /* declare main API struct */
1077 bcmolt_itupon_gem_key key = {}; /* declare key */
1078 bcmolt_gem_port_configuration configuration = {};
Girish Gowdra72cbee92021-11-05 15:16:18 -07001079 bcmolt_onu_state onu_state;
Girish Gowdraddf9a162020-01-27 12:56:27 +05301080
1081 key.pon_ni = intf_id;
1082 key.gem_port_id = gemport_id;
1083
1084 BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
1085
1086 bcmolt_gem_port_direction configuration_direction;
1087 configuration_direction = BCMOLT_GEM_PORT_DIRECTION_BIDIRECTIONAL;
1088 BCMOLT_FIELD_SET(&configuration, gem_port_configuration, direction, configuration_direction);
1089
1090 bcmolt_gem_port_type configuration_type;
1091 configuration_type = BCMOLT_GEM_PORT_TYPE_UNICAST;
1092 BCMOLT_FIELD_SET(&configuration, gem_port_configuration, type, configuration_type);
1093
1094 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, configuration, configuration);
1095
1096 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, onu_id, onu_id);
1097
1098 bcmolt_control_state encryption_mode;
1099 encryption_mode = BCMOLT_CONTROL_STATE_DISABLE;
1100 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
1101
1102 bcmolt_us_gem_port_destination upstream_destination_queue;
1103 upstream_destination_queue = BCMOLT_US_GEM_PORT_DESTINATION_DATA;
1104 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, upstream_destination_queue, upstream_destination_queue);
1105
1106 bcmolt_control_state control;
1107 control = BCMOLT_CONTROL_STATE_ENABLE;
1108 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, control, control);
1109
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301110 bool wait_for_gem_cfg_complt = false;
1111 if (board_technology == "GPON") {
1112 // Wait for gem cfg complete indication only if ONU state is ACTIVE
1113 err = get_onu_state((bcmolt_interface)intf_id, (bcmolt_onu_id)onu_id, &onu_state);
1114 if (err) {
1115 OPENOLT_LOG(ERROR, openolt_log_id, "failed to get onu status onu_id = %d, gem_port = %d err = %s\n", onu_id, gemport_id, bcmos_strerror(err));
1116 return bcm_to_grpc_err(err, "failed to get onu status");
1117 } else if (onu_state == BCMOLT_ONU_STATE_ACTIVE) {
1118 wait_for_gem_cfg_complt = true;
1119 }
1120 }
1121
Girish Gowdraddf9a162020-01-27 12:56:27 +05301122 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
1123 if(err != BCM_ERR_OK) {
Burak Gurdaga0523592021-02-24 15:17:47 +00001124 OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d err = %s (%d)\n", gemport_id, cfg.hdr.hdr.err_text, err);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301125 return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
1126 }
1127
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301128 // Wait for gem cfg complete indication only if ONU state is ACTIVE
1129 if (wait_for_gem_cfg_complt) {
1130 err = wait_for_gem_action(intf_id, gemport_id, GEM_OBJECT_CREATE);
1131 if (err) {
1132 OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d err = %s\n", gemport_id, bcmos_strerror(err));
1133 return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
Thiyagarajan Subramani19168f52021-05-25 23:26:41 +05301134 }
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301135 } else {
1136 OPENOLT_LOG(DEBUG, openolt_log_id, "not waiting for gem config complete indication = %d\n", gemport_id);
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301137 }
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301138
Girish Gowdraddf9a162020-01-27 12:56:27 +05301139 OPENOLT_LOG(INFO, openolt_log_id, "gem port installed successfully = %d\n", gemport_id);
1140
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301141 bcmos_fastlock_lock(&data_lock);
1142 gemport_status_map[gem_status_key] = true;
1143 bcmos_fastlock_unlock(&data_lock, 0);
1144
Girish Gowdraddf9a162020-01-27 12:56:27 +05301145 return Status::OK;
1146}
1147
Thiyagarajan Subramani19168f52021-05-25 23:26:41 +05301148Status remove_gem_port(int32_t intf_id, int32_t onu_id, int32_t uni_id, int32_t gemport_id, std::string board_technology) {
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301149 gemport_status_map_key_tuple gem_status_key(intf_id, onu_id, uni_id, gemport_id);
Girish Gowdra72cbee92021-11-05 15:16:18 -07001150 bcmolt_onu_state onu_state;
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301151
1152 bcmos_fastlock_lock(&data_lock);
1153 std::map<gemport_status_map_key_tuple, bool>::const_iterator it = gemport_status_map.find(gem_status_key);
1154 if (it == gemport_status_map.end()) {
1155 bcmos_fastlock_unlock(&data_lock, 0);
1156 OPENOLT_LOG(INFO, openolt_log_id, "gem port already removed = %d\n", gemport_id);
1157 return Status::OK;
1158 }
1159 bcmos_fastlock_unlock(&data_lock, 0);
1160
Girish Gowdraddf9a162020-01-27 12:56:27 +05301161 bcmolt_itupon_gem_cfg gem_cfg;
1162 bcmolt_itupon_gem_key key = {
1163 .pon_ni = (bcmolt_interface)intf_id,
1164 .gem_port_id = (bcmolt_gem_port_id)gemport_id
1165 };
1166 bcmos_errno err;
1167
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301168 bool wait_for_gem_cfg_complt = false;
1169 if (board_technology == "GPON") {
1170 // Wait for gem cfg complete indication only if ONU state is ACTIVE
1171 err = get_onu_state((bcmolt_interface)intf_id, (bcmolt_onu_id)onu_id, &onu_state);
1172 if (err) {
1173 OPENOLT_LOG(ERROR, openolt_log_id, "failed to get onu status onu_id = %d, gem_port = %d err = %s\n", onu_id, gemport_id, bcmos_strerror(err));
1174 return bcm_to_grpc_err(err, "failed to get onu status");
1175 } else if (onu_state == BCMOLT_ONU_STATE_ACTIVE) {
1176 wait_for_gem_cfg_complt = true;
1177 }
1178 }
1179
Girish Gowdraddf9a162020-01-27 12:56:27 +05301180 BCMOLT_CFG_INIT(&gem_cfg, itupon_gem, key);
1181 err = bcmolt_cfg_clear(dev_id, &gem_cfg.hdr);
1182 if (err != BCM_ERR_OK)
1183 {
Burak Gurdaga0523592021-02-24 15:17:47 +00001184 OPENOLT_LOG(ERROR, openolt_log_id, "failed to remove gem_port = %d err = %s (%d)\n", gemport_id, gem_cfg.hdr.hdr.err_text, err);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301185 return bcm_to_grpc_err(err, "Access_Control clear ITU PON Gem port failed");
1186 }
1187
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301188 if (wait_for_gem_cfg_complt) {
1189 OPENOLT_LOG(INFO, openolt_log_id, "onu state is active waiting for gem cfg complete indication intf = %d onu = %d\n",
Girish Gowdra72cbee92021-11-05 15:16:18 -07001190 intf_id, onu_id);
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301191 err = wait_for_gem_action(intf_id, gemport_id, GEM_OBJECT_DELETE);
1192 if (err) {
1193 OPENOLT_LOG(ERROR, openolt_log_id, "Failed to remove gem, intf_id %d, gemport_id %d, err = %s\n",
Girish Gowdra72cbee92021-11-05 15:16:18 -07001194 intf_id, gemport_id, bcmos_strerror(err));
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301195 return bcm_to_grpc_err(err, "failed to remove gem");
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301196 }
Girish Gowdracdd5e5f2021-12-05 16:48:08 +05301197 } else {
1198 OPENOLT_LOG(DEBUG, openolt_log_id, "onu not active or/and not gpon tech, not waiting for gem cfg complete, onu_state = %d, intf = %d, gemport_id = %d, onu=%d\n",
1199 onu_state, intf_id, gemport_id, onu_id);
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301200 }
1201
Girish Gowdraddf9a162020-01-27 12:56:27 +05301202 OPENOLT_LOG(INFO, openolt_log_id, "gem port removed successfully = %d\n", gemport_id);
1203
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301204 bcmos_fastlock_lock(&data_lock);
1205 it = gemport_status_map.find(gem_status_key);
1206 if (it != gemport_status_map.end()) {
1207 gemport_status_map.erase(it);
1208 }
1209 bcmos_fastlock_unlock(&data_lock, 0);
1210
Girish Gowdraddf9a162020-01-27 12:56:27 +05301211 return Status::OK;
1212}
1213
Thiyagarajan Subramani19168f52021-05-25 23:26:41 +05301214Status enable_encryption_for_gem_port(int32_t intf_id, int32_t gemport_id, std::string board_technology) {
Burak Gurdaga0523592021-02-24 15:17:47 +00001215 bcmos_errno err;
1216 bcmolt_itupon_gem_cfg cfg;
1217 bcmolt_itupon_gem_key key = {
1218 .pon_ni = (bcmolt_interface)intf_id,
1219 .gem_port_id = (bcmolt_gem_port_id)gemport_id
1220 };
1221
1222 BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
Thiyagarajan Subramaniff9d5ef2021-06-17 12:07:49 +05301223 BCMOLT_MSG_FIELD_GET(&cfg, encryption_mode);
1224 err = bcmolt_cfg_get(dev_id, &cfg.hdr);
1225 if (err != BCM_ERR_OK) {
Girish Gowdra72cbee92021-11-05 15:16:18 -07001226 OPENOLT_LOG(ERROR, openolt_log_id, "GEM port get encryption_mode failed err = %s (%d)\n", cfg.hdr.hdr.err_text, err);
Thiyagarajan Subramaniff9d5ef2021-06-17 12:07:49 +05301227 return bcm_to_grpc_err(err, "GEM port get encryption_mode failed");
1228 }
1229
1230 if (cfg.data.encryption_mode == BCMOLT_CONTROL_STATE_ENABLE) {
1231 OPENOLT_LOG(INFO, openolt_log_id, "gem port already encrypted = %d\n", gemport_id);
1232 return Status::OK;
1233 }
Burak Gurdaga0523592021-02-24 15:17:47 +00001234
1235 bcmolt_control_state encryption_mode;
1236 encryption_mode = BCMOLT_CONTROL_STATE_ENABLE;
1237 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
1238
1239 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
1240 if(err != BCM_ERR_OK) {
1241 OPENOLT_LOG(ERROR, openolt_log_id, "failed to set encryption on pon = %d gem_port = %d, err = %s (%d)\n",
1242 intf_id, gemport_id, cfg.hdr.hdr.err_text, err);
1243 return bcm_to_grpc_err(err, "Failed to set encryption on GEM port");;
1244 }
1245
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301246#ifndef SCALE_AND_PERF
Thiyagarajan Subramani19168f52021-05-25 23:26:41 +05301247 if (board_technology == "GPON") {
1248 err = wait_for_gem_action(intf_id, gemport_id, GEM_OBJECT_ENCRYPT);
1249 if (err) {
1250 OPENOLT_LOG(ERROR, openolt_log_id, "failed to enable gemport encryption, gem_port = %d err = %s\n", gemport_id, bcmos_strerror(err));
1251 return bcm_to_grpc_err(err, "Access_Control ITU PON Gem port encryption failed");
1252 }
Thiyagarajan Subramanie976fcf2021-05-07 22:46:57 +05301253 }
1254#endif
1255
Burak Gurdaga0523592021-02-24 15:17:47 +00001256 OPENOLT_LOG(INFO, openolt_log_id, "encryption set successfully on pon = %d gem_port = %d\n", intf_id, gemport_id);
1257
1258 return Status::OK;
1259}
1260
Girish Gowdraddf9a162020-01-27 12:56:27 +05301261Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
1262 bcmolt_members_update_command acl_cmd) {
1263 bcmos_errno err;
1264 bcmolt_access_control_interfaces_update oper; /* declare main API struct */
1265 bcmolt_access_control_key acl_key = {}; /* declare key */
1266 bcmolt_intf_ref interface_ref_list_elem = {};
1267 bcmolt_interface_type interface_ref_list_elem_intf_type;
1268 bcmolt_interface_id interface_ref_list_elem_intf_id;
1269 bcmolt_intf_ref_list_u8 interface_ref_list = {};
1270
1271 if (acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_ADD && acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) {
1272 OPENOLT_LOG(ERROR, openolt_log_id, "acl cmd = %d not supported currently\n", acl_cmd);
1273 return bcm_to_grpc_err(BCM_ERR_PARM, "unsupported acl cmd");
1274 }
1275 interface_ref_list.arr = (bcmolt_intf_ref*)bcmos_calloc(sizeof(bcmolt_intf_ref)*1);
1276
1277 if (interface_ref_list.arr == NULL)
1278 return bcm_to_grpc_err(BCM_ERR_PARM, "allocate interface_ref_list failed");
1279 OPENOLT_LOG(INFO, openolt_log_id, "update acl interface received for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
1280 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
1281 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
1282
1283 acl_key.id = access_control_id;
1284
1285 /* Initialize the API struct. */
1286 BCMOLT_OPER_INIT(&oper, access_control, interfaces_update, acl_key);
1287
1288 bcmolt_members_update_command command;
1289 command = acl_cmd;
1290 BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, command, command);
1291
1292 interface_ref_list_elem_intf_type = intf_type;
1293 BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_type, interface_ref_list_elem_intf_type);
1294
1295 interface_ref_list_elem_intf_id = intf_id;
1296 BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_id, interface_ref_list_elem_intf_id);
1297
1298 interface_ref_list.len = 1;
1299 BCMOLT_ARRAY_ELEM_SET(&interface_ref_list, 0, interface_ref_list_elem);
1300
1301 BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, interface_ref_list, interface_ref_list);
1302
1303 err = bcmolt_oper_submit(dev_id, &oper.hdr);
1304 if (err != BCM_ERR_OK) {
1305 OPENOLT_LOG(ERROR, openolt_log_id, "update acl interface fail for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
1306 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
1307 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
1308 return bcm_to_grpc_err(err, "Access_Control submit interface failed");
1309 }
1310
1311 bcmos_free(interface_ref_list.arr);
1312 OPENOLT_LOG(INFO, openolt_log_id, "update acl interface success for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
1313 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
1314 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
1315
1316 return Status::OK;
1317}
1318
1319Status install_acl(const acl_classifier_key acl_key) {
Girish Gowdraddf9a162020-01-27 12:56:27 +05301320 bcmos_errno err;
1321 bcmolt_access_control_cfg cfg;
1322 bcmolt_access_control_key key = { };
1323 bcmolt_classifier c_val = { };
1324 // hardcode the action for now.
1325 bcmolt_access_control_fwd_action_type action_type = BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST;
Girish Gowdraddf9a162020-01-27 12:56:27 +05301326 int acl_id = get_acl_id();
1327 if (acl_id < 0) {
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001328 OPENOLT_LOG(ERROR, openolt_log_id, "exhausted acl_id for eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d o_vid = %d, max_acl_hit=%d\n",
1329 acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port, acl_key.o_vid, max_acls_with_vlan_classifiers_hit);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301330 return bcm_to_grpc_err(BCM_ERR_INTERNAL, "exhausted acl id");
1331 }
1332
1333 key.id = acl_id;
1334 /* config access control instance */
1335 BCMOLT_CFG_INIT(&cfg, access_control, key);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301336 if (acl_key.ether_type > 0) {
1337 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ether_type 0x%04x\n", acl_key.ether_type);
1338 BCMOLT_FIELD_SET(&c_val, classifier, ether_type, acl_key.ether_type);
1339 }
1340
1341 if (acl_key.ip_proto > 0) {
1342 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ip_proto %d\n", acl_key.ip_proto);
1343 BCMOLT_FIELD_SET(&c_val, classifier, ip_proto, acl_key.ip_proto);
1344 }
1345
1346 if (acl_key.dst_port > 0) {
1347 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify dst_port %d\n", acl_key.dst_port);
1348 BCMOLT_FIELD_SET(&c_val, classifier, dst_port, acl_key.dst_port);
1349 }
1350
1351 if (acl_key.src_port > 0) {
1352 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify src_port %d\n", acl_key.src_port);
1353 BCMOLT_FIELD_SET(&c_val, classifier, src_port, acl_key.src_port);
1354 }
1355
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001356 // Make sure that max_acls_with_vlan_classifiers_hit is not true to consider o_vid for ACL classification.
1357 if (acl_key.o_vid > 0 && acl_key.o_vid != ANY_VLAN && !max_acls_with_vlan_classifiers_hit) {
1358 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify o_vid %d\n", acl_key.o_vid);
1359 BCMOLT_FIELD_SET(&c_val, classifier, o_vid, acl_key.o_vid);
1360 }
1361
Girish Gowdraddf9a162020-01-27 12:56:27 +05301362 BCMOLT_MSG_FIELD_SET(&cfg, classifier, c_val);
1363 BCMOLT_MSG_FIELD_SET(&cfg, priority, 10000);
1364 BCMOLT_MSG_FIELD_SET(&cfg, statistics_control, BCMOLT_CONTROL_STATE_ENABLE);
1365
1366 BCMOLT_MSG_FIELD_SET(&cfg, forwarding_action.action, action_type);
1367
1368 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
1369 if (err != BCM_ERR_OK) {
Girish Gowdra72cbee92021-11-05 15:16:18 -07001370 OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control set configuration failed, err = %s (%d)\n", cfg.hdr.hdr.err_text, err);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301371 // Free the acl_id
1372 free_acl_id(acl_id);
1373 return bcm_to_grpc_err(err, "Access_Control set configuration failed");
1374 }
1375
1376 ACL_LOG(INFO, "ACL add ok", err);
1377
1378 // Update the map that we have installed an acl for the given classfier.
1379 acl_classifier_to_acl_id_map[acl_key] = acl_id;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001380 // If there was a valid vlan classifier in the ACL and the ACL ID hit the ceiling, set max_acls_with_vlan_classifiers_hit to true
1381 // After max_acls_with_vlan_classifiers_hit is set to true no more ACLs can have vlan as an ACL classifier.
1382 if (acl_key.o_vid > 0 && acl_key.o_vid != ANY_VLAN && acl_id >= MAX_ACL_WITH_VLAN_CLASSIFIER) {
1383 max_acls_with_vlan_classifiers_hit = true;
1384 }
Girish Gowdraddf9a162020-01-27 12:56:27 +05301385 return Status::OK;
1386}
1387
1388Status remove_acl(int acl_id) {
1389 bcmos_errno err;
1390 bcmolt_access_control_cfg cfg; /* declare main API struct */
1391 bcmolt_access_control_key key = {}; /* declare key */
1392
1393 key.id = acl_id;
1394
1395 /* Initialize the API struct. */
1396 BCMOLT_CFG_INIT(&cfg, access_control, key);
1397 BCMOLT_FIELD_SET_PRESENT(&cfg.data, access_control_cfg_data, state);
1398 err = bcmolt_cfg_get(dev_id, &cfg.hdr);
1399 if (err != BCM_ERR_OK) {
Girish Gowdra72cbee92021-11-05 15:16:18 -07001400 OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control get state failed, err = %s (%d)\n", cfg.hdr.hdr.err_text, err);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301401 return bcm_to_grpc_err(err, "Access_Control get state failed");
1402 }
1403
1404 if (cfg.data.state == BCMOLT_CONFIG_STATE_CONFIGURED) {
1405 key.id = acl_id;
1406 /* Initialize the API struct. */
1407 BCMOLT_CFG_INIT(&cfg, access_control, key);
1408
1409 err = bcmolt_cfg_clear(dev_id, &cfg.hdr);
1410 if (err != BCM_ERR_OK) {
1411 // Should we free acl_id here ? We should ideally never land here..
Girish Gowdra72cbee92021-11-05 15:16:18 -07001412 OPENOLT_LOG(ERROR, openolt_log_id, "Error %d while removing Access_Control rule ID err = %s (%d)\n",
1413 acl_id, cfg.hdr.hdr.err_text, err);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301414 return Status(grpc::StatusCode::INTERNAL, "Failed to remove Access_Control");
1415 }
1416 }
1417
1418 // Free up acl_id
1419 free_acl_id(acl_id);
1420
1421 OPENOLT_LOG(INFO, openolt_log_id, "acl removed successfully %d\n", acl_id);
1422
1423 return Status::OK;
1424}
1425
1426// Formulates ACL Classifier Key based on the following fields
1427// a. ether_type b. ip_proto c. src_port d. dst_port
1428// If any of the field is not available it is populated as -1.
1429void formulate_acl_classifier_key(acl_classifier_key *key, const ::openolt::Classifier& classifier) {
1430
1431 // TODO: Is 0 a valid value for any of the following classifiers?
1432 // because in the that case, the 'if' check would fail and -1 would be filled as value.
1433 //
1434 if (classifier.eth_type()) {
1435 OPENOLT_LOG(DEBUG, openolt_log_id, "classify ether_type 0x%04x\n", classifier.eth_type());
1436 key->ether_type = classifier.eth_type();
1437 } else key->ether_type = -1;
1438
1439 if (classifier.ip_proto()) {
1440 OPENOLT_LOG(DEBUG, openolt_log_id, "classify ip_proto %d\n", classifier.ip_proto());
1441 key->ip_proto = classifier.ip_proto();
1442 } else key->ip_proto = -1;
1443
1444
1445 if (classifier.src_port()) {
1446 OPENOLT_LOG(DEBUG, openolt_log_id, "classify src_port %d\n", classifier.src_port());
1447 key->src_port = classifier.src_port();
1448 } else key->src_port = -1;
1449
1450
1451 if (classifier.dst_port()) {
1452 OPENOLT_LOG(DEBUG, openolt_log_id, "classify dst_port %d\n", classifier.dst_port());
1453 key->dst_port = classifier.dst_port();
1454 } else key->dst_port = -1;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001455
1456 // We should also check the max_acls_with_vlan_classifiers_hit flag is not false to consider the vlan for flow classifier key
1457 if (classifier.o_vid() && !max_acls_with_vlan_classifiers_hit) {
1458 OPENOLT_LOG(DEBUG, openolt_log_id, "classify o_vid %d\n", classifier.o_vid());
1459 key->o_vid = classifier.o_vid();
1460 } else key->o_vid = ANY_VLAN;
1461
Girish Gowdraddf9a162020-01-27 12:56:27 +05301462}
1463
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001464Status handle_acl_rule_install(int32_t onu_id, uint64_t flow_id, int32_t gemport_id,
Girish Gowdraddf9a162020-01-27 12:56:27 +05301465 const std::string flow_type, int32_t access_intf_id,
Girish Gowdra252f4972020-09-07 21:24:01 -07001466 int32_t network_intf_id,
Girish Gowdraddf9a162020-01-27 12:56:27 +05301467 const ::openolt::Classifier& classifier) {
1468 int acl_id;
Girish Gowdrafc6c0bf2022-01-28 18:31:30 -08001469 uint32_t intf_id = flow_type == upstream? access_intf_id: network_intf_id;
1470 const std::string intf_type = flow_type == upstream? "pon": "nni";
Girish Gowdraddf9a162020-01-27 12:56:27 +05301471 bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
1472
1473 Status resp;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001474 trap_to_host_packet_type pkt_type = get_trap_to_host_packet_type(classifier);
1475 if (pkt_type == unsupported_trap_to_host_pkt_type) {
1476 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported pkt trap type");
1477 return Status(grpc::StatusCode::UNIMPLEMENTED, "unsupported pkt trap type");
1478 }
Girish Gowdraddf9a162020-01-27 12:56:27 +05301479
1480 // few map keys we are going to use later.
1481 flow_id_flow_direction fl_id_fl_dir(flow_id, flow_type);
Girish Gowdra252f4972020-09-07 21:24:01 -07001482
Girish Gowdraddf9a162020-01-27 12:56:27 +05301483 acl_classifier_key acl_key;
1484 formulate_acl_classifier_key(&acl_key, classifier);
1485 const acl_classifier_key acl_key_const = {.ether_type=acl_key.ether_type, .ip_proto=acl_key.ip_proto,
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001486 .src_port=acl_key.src_port, .dst_port=acl_key.dst_port, .o_vid=acl_key.o_vid};
1487 bcmos_fastlock_lock(&acl_packet_trap_handler_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301488
1489 // Check if the acl is already installed
1490 if (acl_classifier_to_acl_id_map.count(acl_key_const) > 0) {
1491 // retreive the acl_id
1492 acl_id = acl_classifier_to_acl_id_map[acl_key_const];
Girish Gowdra252f4972020-09-07 21:24:01 -07001493
1494
Girish Gowdraddf9a162020-01-27 12:56:27 +05301495 if (flow_to_acl_map.count(fl_id_fl_dir)) {
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001496 // could happen if same trap flow is received again
Girish Gowdraddf9a162020-01-27 12:56:27 +05301497 OPENOLT_LOG(INFO, openolt_log_id, "flow and related acl already handled, nothing more to do\n");
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001498 bcmos_fastlock_unlock(&acl_packet_trap_handler_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301499 return Status::OK;
1500 }
1501
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001502 OPENOLT_LOG(INFO, openolt_log_id, "Acl for flow_id=%lu with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d o_vid = %d already installed with acl id = %u\n",
1503 flow_id, acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port, acl_key.o_vid, acl_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301504
1505 // The acl_ref_cnt is needed to know how many flows refer an ACL.
1506 // When the flow is removed, we decrement the reference count.
1507 // When the reference count becomes 0, we remove the ACL.
1508 if (acl_ref_cnt.count(acl_id) > 0) {
1509 acl_ref_cnt[acl_id] ++;
1510 } else {
1511 // We should ideally not land here. The acl_ref_cnt should have been
1512 // initialized the first time acl was installed.
1513 acl_ref_cnt[acl_id] = 1;
1514 }
1515
1516 } else {
1517 resp = install_acl(acl_key_const);
1518 if (!resp.ok()) {
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001519 OPENOLT_LOG(ERROR, openolt_log_id, "Acl for flow_id=%lu with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d o_vid = %d failed\n",
1520 flow_id, acl_key_const.ether_type, acl_key_const.ip_proto, acl_key_const.src_port, acl_key_const.dst_port, acl_key_const.o_vid);
1521 bcmos_fastlock_unlock(&acl_packet_trap_handler_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301522 return resp;
1523 }
1524
1525 acl_id = acl_classifier_to_acl_id_map[acl_key_const];
1526
1527 // Initialize the acl reference count
1528 acl_ref_cnt[acl_id] = 1;
1529
Girish Gowdra252f4972020-09-07 21:24:01 -07001530 OPENOLT_LOG(INFO, openolt_log_id, "acl add success for flow_id=%lu with acl_id=%d\n", flow_id, acl_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301531 }
1532
1533 // Register the interface for the given acl
1534 acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
1535 // This is needed to keep a track of which interface (pon/nni) has registered for an ACL.
1536 // If it is registered, how many flows refer to it.
1537 if (intf_acl_registration_ref_cnt.count(ac_id_inf_id_inf_type) > 0) {
1538 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]++;
1539 } else {
1540 // The given interface is not registered for the ACL. We need to do it now.
1541 resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_ADD);
1542 if (!resp.ok()){
1543 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);
1544 // TODO: Ideally we should return error from hear and clean up other other stateful
1545 // counters we creaed earlier. Will leave it out for now.
Girish Gowdra252f4972020-09-07 21:24:01 -07001546 }
Girish Gowdraddf9a162020-01-27 12:56:27 +05301547 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] = 1;
1548 }
1549
Girish Gowdra252f4972020-09-07 21:24:01 -07001550 acl_id_intf_id ac_id_if_id(acl_id, intf_id);
1551 flow_to_acl_map[fl_id_fl_dir] = ac_id_if_id;
Girish Gowdraddf9a162020-01-27 12:56:27 +05301552
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001553 // Populate the trap_to_host_pkt_info_with_vlan corresponding to the trap-to-host voltha flow_id key.
1554 // When the trap-to-host voltha flow-id is being removed, this entry is cleared too from the map.
1555 trap_to_host_pkt_info_with_vlan pkt_info_with_vlan((int32_t)olt_if_type, intf_id, (int32_t)pkt_type, gemport_id, (short unsigned int)classifier.o_vid());
1556 trap_to_host_pkt_info_with_vlan_for_flow_id[flow_id] = pkt_info_with_vlan;
1557 trap_to_host_pkt_info pkt_info((int32_t)olt_if_type, intf_id, (int32_t)pkt_type, gemport_id);
1558 bool duplicate = false;
1559 // Check if the vlan_id corresponding to the trap_to_host_pkt_info key is found. Set the 'duplicate' flag accordingly.
1560 if (trap_to_host_vlan_ids_for_trap_to_host_pkt_info.count(pkt_info) > 0) {
1561 auto& vlan_id_list = trap_to_host_vlan_ids_for_trap_to_host_pkt_info[pkt_info];
1562 auto it = std::find(vlan_id_list.begin(), vlan_id_list.end(), acl_key.o_vid);
1563 if (it != vlan_id_list.end()) {
1564 OPENOLT_LOG(DEBUG, openolt_log_id, "cvid = %d exists already in list", acl_key.o_vid);
1565 duplicate = true;
1566 }
1567 }
1568 // If the vlan_id is not found corresponding to the trap_to_host_pkt_info key, update it.
1569 // This will be used to validate the vlan_id in the trapped packet. If vlan_id in the
1570 // trapped packet is not match with the stored value, packet is dropped.
1571 if (!duplicate) {
1572 trap_to_host_vlan_ids_for_trap_to_host_pkt_info[pkt_info].push_back(acl_key.o_vid);
1573 }
1574
1575 bcmos_fastlock_unlock(&acl_packet_trap_handler_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301576
1577 return Status::OK;
1578}
1579
Girish Gowdra252f4972020-09-07 21:24:01 -07001580Status handle_acl_rule_cleanup(int16_t acl_id, int32_t intf_id, const std::string flow_type) {
Girish Gowdrafc6c0bf2022-01-28 18:31:30 -08001581 const std::string intf_type= flow_type == upstream? "pon": "nni";
Girish Gowdraddf9a162020-01-27 12:56:27 +05301582 acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
1583 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]--;
1584 if (intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] == 0) {
1585 bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
1586 Status resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE);
1587 if (!resp.ok()){
1588 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);
1589 }
1590 intf_acl_registration_ref_cnt.erase(ac_id_inf_id_inf_type);
1591 }
1592
1593 acl_ref_cnt[acl_id]--;
1594 if (acl_ref_cnt[acl_id] == 0) {
1595 remove_acl(acl_id);
1596 acl_ref_cnt.erase(acl_id);
1597 // Iterate acl_classifier_to_acl_id_map and delete classifier the key corresponding to acl_id
1598 std::map<acl_classifier_key, uint16_t>::iterator it;
1599 for (it=acl_classifier_to_acl_id_map.begin(); it!=acl_classifier_to_acl_id_map.end(); ++it) {
1600 if (it->second == acl_id) {
1601 OPENOLT_LOG(INFO, openolt_log_id, "cleared classifier key corresponding to acl_id = %d\n", acl_id);
1602 acl_classifier_to_acl_id_map.erase(it->first);
1603 break;
1604 }
1605 }
1606 }
1607
Girish Gowdraddf9a162020-01-27 12:56:27 +05301608 return Status::OK;
1609}
1610
1611Status check_bal_ready() {
1612 bcmos_errno err;
1613 int maxTrials = 30;
1614 bcmolt_olt_cfg olt_cfg = { };
1615 bcmolt_olt_key olt_key = { };
1616
1617 BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
1618 BCMOLT_MSG_FIELD_GET(&olt_cfg, bal_state);
1619
1620 while (olt_cfg.data.bal_state != BCMOLT_BAL_STATE_BAL_AND_SWITCH_READY) {
1621 if (--maxTrials == 0)
1622 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check bal ready failed");
1623 sleep(5);
1624 #ifdef TEST_MODE
1625 // It is impossible to mock the setting of olt_cfg.data.bal_state because
1626 // the actual bcmolt_cfg_get passes the address of olt_cfg.hdr and we cannot
1627 // set the olt_cfg.data.bal_state. So a new stub function is created and address
1628 // of olt_cfg is passed. This is one-of case where we need to add test specific
1629 // code in production code.
1630 if (bcmolt_cfg_get__bal_state_stub(dev_id, &olt_cfg)) {
1631 #else
1632 if (bcmolt_cfg_get(dev_id, &olt_cfg.hdr)) {
1633 #endif
1634 continue;
1635 }
1636 else
1637 OPENOLT_LOG(INFO, openolt_log_id, "waiting for BAL ready ...\n");
1638 }
1639
1640 OPENOLT_LOG(INFO, openolt_log_id, "BAL is ready\n");
1641 return Status::OK;
1642}
1643
1644Status check_connection() {
1645 int maxTrials = 60;
1646 while (!bcmolt_api_conn_mgr_is_connected(dev_id)) {
1647 sleep(1);
1648 if (--maxTrials == 0)
1649 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check connection failed");
1650 else
1651 OPENOLT_LOG(INFO, openolt_log_id, "waiting for daemon connection ...\n");
1652 }
1653 OPENOLT_LOG(INFO, openolt_log_id, "daemon is connected\n");
1654 return Status::OK;
1655}
1656
Thiyagarajan Subramani03bc66f2020-04-01 15:58:53 +05301657std::string get_ip_address(const char* nw_intf){
1658 std::string ipAddress = "0.0.0.0";
1659 struct ifaddrs *interfaces = NULL;
1660 struct ifaddrs *temp_addr = NULL;
1661 int success = 0;
1662 /* retrieve the current interfaces - returns 0 on success */
1663 success = getifaddrs(&interfaces);
1664 if (success == 0) {
1665 /* Loop through linked list of interfaces */
1666 temp_addr = interfaces;
1667 while(temp_addr != NULL) {
1668 if(temp_addr->ifa_addr->sa_family == AF_INET) {
1669 /* Check if interface given present in OLT, if yes return its IP Address */
1670 if(strcmp(temp_addr->ifa_name, nw_intf) == 0){
1671 ipAddress=inet_ntoa(((struct sockaddr_in*)temp_addr->ifa_addr)->sin_addr);
1672 break;
1673 }
1674 }
1675 temp_addr = temp_addr->ifa_next;
1676 }
1677 }
1678 /* Free memory */
1679 freeifaddrs(interfaces);
1680 return ipAddress;
1681}
Jason Huang1d9cfce2020-05-20 22:58:47 +08001682
1683bcmos_errno getOnuMaxLogicalDistance(uint32_t intf_id, uint32_t *mld) {
1684 bcmos_errno err = BCM_ERR_OK;
1685 bcmolt_pon_distance pon_distance = {};
1686 bcmolt_pon_interface_cfg pon_cfg; /* declare main API struct */
1687 bcmolt_pon_interface_key key = {}; /* declare key */
1688
1689 key.pon_ni = intf_id;
1690
1691 if (!state.is_activated()) {
1692 OPENOLT_LOG(ERROR, openolt_log_id, "ONU maximum logical distance is not available since OLT is not activated yet\n");
1693 return BCM_ERR_STATE;
1694 }
1695
1696 /* Initialize the API struct. */
1697 BCMOLT_CFG_INIT(&pon_cfg, pon_interface, key);
1698 BCMOLT_FIELD_SET_PRESENT(&pon_distance, pon_distance, max_log_distance);
1699 BCMOLT_FIELD_SET(&pon_cfg.data, pon_interface_cfg_data, pon_distance, pon_distance);
1700 #ifdef TEST_MODE
1701 // It is impossible to mock the setting of pon_cfg.data.state because
1702 // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
1703 // set the pon_cfg.data.state. So a new stub function is created and address
1704 // of pon_cfg is passed. This is one-of case where we need to add test specific
1705 // code in production code.
1706 err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
1707 #else
1708 err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
1709 #endif
1710 if (err != BCM_ERR_OK) {
Girish Gowdra72cbee92021-11-05 15:16:18 -07001711 OPENOLT_LOG(ERROR, openolt_log_id, "Failed to retrieve ONU maximum logical distance for PON %d, err = %s (%d)\n", intf_id, pon_cfg.hdr.hdr.err_text, err);
Jason Huang1d9cfce2020-05-20 22:58:47 +08001712 return err;
1713 }
1714 *mld = pon_distance.max_log_distance;
1715
1716 return BCM_ERR_OK;
1717}
Humera Kouser6143c9e2020-06-17 22:37:31 +05301718
1719/**
1720* Gets mac address based on interface name.
1721*
1722* @param intf_name interface name
1723* @param mac_address mac address field
1724* @param max_size_of_mac_address max sixe of the mac_address
1725* @return mac_address value in case of success or return NULL in case of failure.
1726*/
1727
1728char* get_intf_mac(const char* intf_name, char* mac_address, unsigned int max_size_of_mac_address){
1729 int fd;
1730 struct ifreq ifr;
1731 char *mac;
1732
1733 fd = socket(AF_INET, SOCK_DGRAM, 0);
1734 if ( fd == -1) {
1735 OPENOLT_LOG(ERROR, openolt_log_id, "failed to get mac, could not create file descriptor");
1736 return NULL;
1737 }
1738
1739 ifr.ifr_addr.sa_family = AF_INET;
1740 strncpy((char *)ifr.ifr_name , (const char *)intf_name , IFNAMSIZ-1);
1741 if( ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
1742 {
1743 OPENOLT_LOG(ERROR, openolt_log_id, "failed to get mac, ioctl failed and returned err");
1744 close(fd);
1745 return NULL;
1746 }
1747
1748 close(fd);
1749 mac = (char *)ifr.ifr_hwaddr.sa_data;
1750
1751 // formatted mac address
1752 snprintf(mac_address, max_size_of_mac_address, (const char *)"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (unsigned char)mac[0], (unsigned char)mac[1], (unsigned char)mac[2], (unsigned char)mac[3], (unsigned char)mac[4], (unsigned char)mac[5]);
1753
1754 return mac_address;
1755}
Girish Gowdra252f4972020-09-07 21:24:01 -07001756
1757void update_voltha_flow_to_cache(uint64_t voltha_flow_id, device_flow dev_flow) {
1758 OPENOLT_LOG(DEBUG, openolt_log_id, "updating voltha flow=%lu to cache\n", voltha_flow_id)
1759 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1760 voltha_flow_to_device_flow[voltha_flow_id] = dev_flow;
1761 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1762}
1763
1764void remove_voltha_flow_from_cache(uint64_t voltha_flow_id) {
1765 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1766 std::map<uint64_t, device_flow>::const_iterator it = voltha_flow_to_device_flow.find(voltha_flow_id);
1767 if (it != voltha_flow_to_device_flow.end()) {
1768 voltha_flow_to_device_flow.erase(it);
1769 }
1770 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1771}
1772
1773bool is_voltha_flow_installed(uint64_t voltha_flow_id ) {
1774 int count;
1775 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1776 count = voltha_flow_to_device_flow.count(voltha_flow_id);
1777 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1778
1779 return count > 0 ? true : false;
1780}
1781
1782const device_flow_params* get_device_flow_params(uint64_t voltha_flow_id) {
1783 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1784 std::map<uint64_t, device_flow>::const_iterator it = voltha_flow_to_device_flow.find(voltha_flow_id);
1785 if (it != voltha_flow_to_device_flow.end()) {
1786 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1787 return it->second.params;
1788 }
1789 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1790
1791 return NULL;
1792}
1793
1794const device_flow* get_device_flow(uint64_t voltha_flow_id) {
1795 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1796 std::map<uint64_t, device_flow>::const_iterator it = voltha_flow_to_device_flow.find(voltha_flow_id);
1797 if (it != voltha_flow_to_device_flow.end()) {
1798 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1799 return &it->second;
1800 }
1801 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1802
1803 return NULL;
1804}
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001805
1806trap_to_host_packet_type get_trap_to_host_packet_type(const ::openolt::Classifier& classifier) {
1807 trap_to_host_packet_type type = unsupported_trap_to_host_pkt_type;
1808 if (classifier.eth_type() == EAP_ETH_TYPE) {
1809 type = eap;
1810 } else if (classifier.src_port() == DHCP_SERVER_SRC_PORT || classifier.src_port() == DHCP_CLIENT_SRC_PORT) {
1811 type = dhcpv4;
1812 } else if (classifier.eth_type() == LLDP_ETH_TYPE) {
1813 type = lldp;
1814 } else if (classifier.ip_proto() == IGMPv4_PROTOCOL) {
1815 type = igmpv4;
Marcos Aurelio Carrero (Furukawa)c4c56b32021-03-08 12:20:34 -03001816 } else if (classifier.eth_type() == PPPoED_ETH_TYPE) {
Marcos Aurelio Carrero (Furukawa)cfe3e0d2021-03-03 10:36:56 -03001817 type = pppoed;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001818 }
1819
1820 return type;
1821}
1822
1823// is_packet_allowed extracts the VLAN, packet-type, interface-type, interface-id from incoming trap-to-host packet.
1824// Then it verifies if this packet can be allowed upstream to host. It does this by checking if the vlan in the incoming packet
1825//exists in trap_to_host_vlan_ids_for_trap_to_host_pkt_info map for (interface-type, interface-id, packet-type) key.
1826bool is_packet_allowed(bcmolt_access_control_receive_eth_packet_data *data, int32_t gemport_id) {
1827 bcmolt_interface_type intf_type = data->interface_ref.intf_type;
1828 uint32_t intf_id = data->interface_ref.intf_id;
1829 trap_to_host_packet_type pkt_type = unsupported_trap_to_host_pkt_type;
1830 uint16_t vlan_id = 0;
1831 int ethType;
1832
1833 struct timeval dummy_tv = {0, 0};
1834 bool free_memory_of_raw_packet = false; // This indicates the pcap library to not free the message buffer. It will freed by the caller.
1835
1836 pcpp::RawPacket rawPacket(data->buffer.arr, data->buffer.len, dummy_tv, free_memory_of_raw_packet, pcpp::LINKTYPE_ETHERNET);
1837 pcpp::Packet parsedPacket(&rawPacket);
1838 pcpp::EthLayer* ethernetLayer = parsedPacket.getLayerOfType<pcpp::EthLayer>();
1839 if (ethernetLayer == NULL)
1840 {
1841 OPENOLT_LOG(ERROR, openolt_log_id, "Something went wrong, couldn't find Ethernet layer\n");
1842 return false;
1843 }
1844
1845 // Getting Vlan layer
1846 pcpp::VlanLayer* vlanLayer = parsedPacket.getLayerOfType<pcpp::VlanLayer>();
1847 if (vlanLayer == NULL)
1848 {
1849 // Allow Untagged LLDP Ether type packet to trap from NNI
1850 if (ntohs(ethernetLayer->getEthHeader()->etherType) == LLDP_ETH_TYPE && intf_type == BCMOLT_INTERFACE_TYPE_NNI) {
1851 return true;
1852 } else {
1853 OPENOLT_LOG(WARNING, openolt_log_id, "untagged packets other than lldp packets are dropped. ethertype=%d, intftype=%d, intf_id=%d\n",
1854 ntohs(ethernetLayer->getEthHeader()->etherType), intf_type, intf_id);
1855 return false;
1856 }
1857 } else {
1858 ethType = ntohs(vlanLayer->getVlanHeader()->etherType);
1859 if (ethType == EAP_ETH_TYPE) { // single tagged packet with EAPoL payload
1860 vlan_id = vlanLayer->getVlanID();
1861 pkt_type = eap;
Marcos Aurelio Carrero (Furukawa)cfe3e0d2021-03-03 10:36:56 -03001862 } else if (ethType == PPPoED_ETH_TYPE) { // single tagged packet with PPPOeD payload
1863 vlan_id = vlanLayer->getVlanID();
1864 pkt_type = pppoed;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001865 } else if (ethType == IPV4_ETH_TYPE) { // single tagged packet with IPv4 payload
1866 vlan_id = vlanLayer->getVlanID();
1867 vlanLayer->parseNextLayer();
1868 pcpp::IPv4Layer *ipv4Layer = (pcpp::IPv4Layer*)vlanLayer->getNextLayer();
1869 if(ipv4Layer->getIPv4Header()->protocol == UDP_PROTOCOL) { // UDP payload
1870 // Check the UDP Ports to see if it is a DHCPv4 packet
1871 ipv4Layer->parseNextLayer();
1872 pcpp::UdpLayer *udpLayer = (pcpp::UdpLayer*)ipv4Layer->getNextLayer();
1873 if (ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_SERVER_SRC_PORT|| ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_CLIENT_SRC_PORT) {
1874 pkt_type = dhcpv4;
1875 } else {
1876 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported udp source port = %d\n", ntohs(udpLayer->getUdpHeader()->portSrc));
1877 return false;
1878 }
1879 } else if (ipv4Layer->getIPv4Header()->protocol == IGMPv4_PROTOCOL) { // Igmpv4 payload
1880 pkt_type = igmpv4;
1881 } else {
1882 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported ip protocol = %d\n", ipv4Layer->getIPv4Header()->protocol);
1883 return false;
1884 }
1885 } else if (ethType == VLAN_ETH_TYPE) { // double tagged packet
1886
1887 // Trap-to-host from NNI flows do not specify the VLANs, so no vlan validation is necessary.
1888 if (intf_type == BCMOLT_INTERFACE_TYPE_NNI) {
1889 return true;
1890 }
1891
1892 // Here we parse the inner vlan payload and currently support only IPv4 packets
1893
1894 // Extract the vlan_id for trap-to-host packets arriving from the PON
1895 // trap-to-host ACLs from the NNI do not care about VLAN.
1896 if (intf_type == BCMOLT_INTERFACE_TYPE_PON) {
1897 vlan_id = vlanLayer->getVlanID(); // This is the outer vlan id
1898 }
1899 vlanLayer->parseNextLayer();
1900 vlanLayer = (pcpp::VlanLayer*)vlanLayer->getNextLayer(); // Here we extract the inner vlan layer
1901 ethType = ntohs(vlanLayer->getVlanHeader()->etherType);
1902 if (ethType == IPV4_ETH_TYPE) { // IPv4
1903 uint16_t _inner_vlan_id = vlanLayer->getVlanID();
1904 vlanLayer->parseNextLayer();
1905 pcpp::IPv4Layer *ipv4Layer = (pcpp::IPv4Layer*)vlanLayer->getNextLayer(); // here we extract the inner vlan IPv4 payload
1906 if(ipv4Layer->getIPv4Header()->protocol == UDP_PROTOCOL) { // UDP payload
1907 // Check the UDP Ports to see if it is a DHCPv4 packet
1908 ipv4Layer->parseNextLayer();
1909 pcpp::UdpLayer *udpLayer = (pcpp::UdpLayer*)ipv4Layer->getNextLayer();
1910 if (ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_SERVER_SRC_PORT || ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_CLIENT_SRC_PORT) {
1911 pkt_type = dhcpv4;
1912 } else {
1913 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported udp source port = %d\n", ntohs(udpLayer->getUdpHeader()->portSrc));
1914 return false;
1915 }
1916 } else if (ipv4Layer->getIPv4Header()->protocol == IGMPv4_PROTOCOL) { // Igmpv4 payload
1917 pkt_type = igmpv4;
1918 } else {
1919 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported ip protocol = %d\n", ipv4Layer->getIPv4Header()->protocol)
1920 return false;
1921 }
1922 }
1923 } else {
1924 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported ether type = 0x%x\n", ntohs((vlanLayer->getVlanHeader()->etherType)));
1925 return false;
1926 }
1927 }
1928
1929#if 0 // Debug logs for test purpose only
1930 std::cout << "vlan of received packet " << vlan_id << " intf_type " << intf_type << " intf_id " <<intf_id << " pkt_type " <<pkt_type << " gem_port_id" << gemport_id << "\n";
1931 for(std::map<trap_to_host_pkt_info, std::list<uint16_t> >::const_iterator it = trap_to_host_vlan_ids_for_trap_to_host_pkt_info.begin();
1932 it != trap_to_host_vlan_ids_for_trap_to_host_pkt_info.end(); ++it)
1933 {
1934 std::cout << "value entries" << " " << std::get<0>(it->first) << " "<< std::get<1>(it->first) << " "<< std::get<2>(it->first) << " "<< std::get<3>(it->first) << "\n\n";
1935 std::cout << "vlans for the above key are => ";
1936 for (std::list<uint16_t>::const_iterator _it=it->second.begin();
1937 _it != it->second.end();
1938 ++_it) {
1939 std::cout << *_it << " ";
1940 }
1941 std::cout << "\n\n";
1942 }
1943#endif
1944
1945 trap_to_host_pkt_info pkt_info(intf_type, intf_id, pkt_type, gemport_id);
1946 // Check for matching vlan only if the trap_to_host_pkt_info exists in the trap_to_host_vlan_ids_for_trap_to_host_pkt_info map
1947 if (trap_to_host_vlan_ids_for_trap_to_host_pkt_info.count(pkt_info) > 0) {
1948 // Iterate throught the vlan list to find matching vlan
1949 auto& vlan_id_list = trap_to_host_vlan_ids_for_trap_to_host_pkt_info[pkt_info];
1950 for (auto allowed_vlan_id : vlan_id_list) {
1951 // Found exact matching vlan in the allowed list of vlans for the trap_to_host_pkt_info key or
1952 // there is generic match ANY_VLAN in the list in the allowed vlan list.
1953 if (allowed_vlan_id == vlan_id || allowed_vlan_id == ANY_VLAN) {
1954 return true;
1955 }
1956 }
1957 }
1958 return false;
1959}
Orhan Kupusoglu1fd77072021-03-23 08:13:25 -07001960
1961std::pair<grpc_ssl_client_certificate_request_type, bool> get_grpc_tls_option(const char* tls_option) {
Girish Gowdra262b6292021-07-21 15:32:17 -07001962 static const std::map<std::string,grpc_ssl_client_certificate_request_type> grpc_security_option_map = {{"GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE",
Orhan Kupusoglu1fd77072021-03-23 08:13:25 -07001963 grpc_ssl_client_certificate_request_type::GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE},
1964 {"GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY",
1965 grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY},
1966 {"GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY",
1967 grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY},
1968 {"GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY",
1969 grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY},
1970 {"GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY",
1971 grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY}};
1972
1973 auto it = grpc_security_option_map.find(tls_option);
1974 if (it == grpc_security_option_map.end()) {
1975 OPENOLT_LOG(ERROR, openolt_log_id, "invalid gRPC Server security option: %s\n", tls_option);
1976 return {grpc_ssl_client_certificate_request_type::GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, false};
1977 } else {
1978 OPENOLT_LOG(INFO, openolt_log_id, "valid gRPC Server security option: %s\n", tls_option);
1979 tls_option_arg = std::string{tls_option};
1980 return {it->second, true};
1981 }
1982}
1983
1984const std::string &get_grpc_tls_option() {
1985 return tls_option_arg;
1986}
1987
1988bool is_grpc_secure() {
1989 return !tls_option_arg.empty();
1990}
1991
1992std::pair<std::string, bool> read_from_txt_file(const std::string& file_name) {
1993 std::ifstream in_file(file_name);
1994
1995 if (!in_file.is_open()) {
1996 OPENOLT_LOG(ERROR, openolt_log_id, "error opening file '%s'\n", file_name.c_str());
1997 return {"", false};
1998 }
1999
2000 std::stringstream buffer;
2001 buffer << in_file.rdbuf();
2002
2003 return {buffer.str(), in_file.good()};
2004}
Orhan Kupusogluec57af02021-05-12 12:38:17 +00002005
2006bool save_to_txt_file(const std::string& file_name, const std::string& content) {
2007 std::ofstream out_file;
2008 out_file.exceptions(std::ofstream::failbit | std::ofstream::badbit);
2009
2010 try {
2011 out_file.open(file_name, std::ios::out | std::ios::trunc);
2012
2013 if (!out_file.is_open()) {
2014 std::cerr << "error while opening file '" << file_name << "'\n";
2015 return false;
2016 }
2017
2018 out_file << content;
2019 out_file.close();
2020
2021 return true;
2022 } catch (const std::ofstream::failure& e) {
2023 std::cerr << "exception while writing to file '" << file_name << "' | err: " << e.what() << '\n';
2024 return false;
2025 }
2026}
Girish Gowdrab0337eb2022-03-25 16:44:21 -07002027
2028pair<string, bool> hex_to_ascii_string(unsigned char* ptr, int length) {
2029 // initialize the ASCII code string as empty.
2030 string ascii = "";
2031 for (size_t i = 0; i < length; i ++)
2032 {
2033 string part = string(1,ptr[i]);
2034 ascii += part;
2035 }
2036 return {ascii, true};
2037}
2038
2039pair<uint32_t, bool> hex_to_uinteger(unsigned char *ptr, int length) {
2040 if (length > 8) {
2041 perror("invalid length of bytes for conversion to uint\n");
2042 return {0, false};
2043 }
2044 uint32_t res = 0;
2045 for (int i = 0; i < length; i++)
2046 {
2047 res = uint32_t(ptr[i]) * pow(2, (length - 1 - i) * 8) + res;
2048 }
2049 return {res, true};
2050}