blob: 59c7cdc376b3515f610a96866125454943c50d6d [file] [log] [blame]
Girish Gowdraddf9a162020-01-27 12:56:27 +05301/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "core_utils.h"
18
19std::string serial_number_to_str(bcmolt_serial_number* serial_number) {
20#define SERIAL_NUMBER_SIZE 12
21 char buff[SERIAL_NUMBER_SIZE+1];
22
23 sprintf(buff, "%c%c%c%c%1X%1X%1X%1X%1X%1X%1X%1X",
24 serial_number->vendor_id.arr[0],
25 serial_number->vendor_id.arr[1],
26 serial_number->vendor_id.arr[2],
27 serial_number->vendor_id.arr[3],
28 serial_number->vendor_specific.arr[0]>>4 & 0x0f,
29 serial_number->vendor_specific.arr[0] & 0x0f,
30 serial_number->vendor_specific.arr[1]>>4 & 0x0f,
31 serial_number->vendor_specific.arr[1] & 0x0f,
32 serial_number->vendor_specific.arr[2]>>4 & 0x0f,
33 serial_number->vendor_specific.arr[2] & 0x0f,
34 serial_number->vendor_specific.arr[3]>>4 & 0x0f,
35 serial_number->vendor_specific.arr[3] & 0x0f);
36
37 return buff;
38}
39
40std::string vendor_specific_to_str(char const * const vendor_specific) {
41 char buff[SERIAL_NUMBER_SIZE+1];
42
43 sprintf(buff, "%1X%1X%1X%1X%1X%1X%1X%1X",
44 vendor_specific[0]>>4 & 0x0f,
45 vendor_specific[0] & 0x0f,
46 vendor_specific[1]>>4 & 0x0f,
47 vendor_specific[1] & 0x0f,
48 vendor_specific[2]>>4 & 0x0f,
49 vendor_specific[2] & 0x0f,
50 vendor_specific[3]>>4 & 0x0f,
51 vendor_specific[3] & 0x0f);
52
53 return buff;
54}
55/**
56* Returns the default NNI (Upstream direction) or PON (Downstream direction) scheduler
57* Every NNI port and PON port have default scheduler.
58* The NNI0 default scheduler ID is 18432, and NNI1 is 18433 and so on.
59* Similarly, PON0 default scheduler ID is 16384. PON1 is 16385 and so on.
60*
61* @param intf_id NNI or PON interface ID
62* @param direction "upstream" or "downstream"
63*
64* @return default scheduler ID for the given interface.
65*/
66
67uint16_t get_dev_id(void) {
68 return dev_id;
69}
70
71int get_default_tm_sched_id(int intf_id, std::string direction) {
72 if (direction.compare(upstream) == 0) {
73 return tm_upstream_sched_id_start + intf_id;
74 } else if (direction.compare(downstream) == 0) {
75 return tm_downstream_sched_id_start + intf_id;
76 }
77 else {
78 OPENOLT_LOG(ERROR, openolt_log_id, "invalid direction - %s\n", direction.c_str());
79 return 0;
80 }
81}
82
83/**
84* Gets a unique tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
85* The tm_sched_id is locally cached in a map, so that it can rendered when necessary.
Burak Gurdag2f2618c2020-04-23 13:20:30 +000086* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem.
87* Note that tech_profile_id is used to differentiate service schedulers in downstream direction.
Girish Gowdraddf9a162020-01-27 12:56:27 +053088*
89* @param intf_id NNI or PON intf ID
90* @param onu_id ONU ID
91* @param uni_id UNI ID
92* @param gemport_id GEM Port ID
93* @param direction Upstream or downstream
Burak Gurdag2f2618c2020-04-23 13:20:30 +000094* @param tech_profile_id Technology Profile ID
Girish Gowdraddf9a162020-01-27 12:56:27 +053095*
96* @return tm_sched_id
97*/
Burak Gurdag2f2618c2020-04-23 13:20:30 +000098uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
99 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530100 int sched_id = -1;
101
Girish Gowdra252f4972020-09-07 21:24:01 -0700102 bcmos_fastlock_lock(&tm_sched_bitset_lock);
103
Girish Gowdraddf9a162020-01-27 12:56:27 +0530104 std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
105 if (it != sched_map.end()) {
106 sched_id = it->second;
107 }
108 if (sched_id != -1) {
Girish Gowdra252f4972020-09-07 21:24:01 -0700109 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530110 return sched_id;
111 }
112
Girish Gowdraddf9a162020-01-27 12:56:27 +0530113 // Complexity of O(n). Is there better way that can avoid linear search?
114 for (sched_id = 0; sched_id < MAX_TM_SCHED_ID; sched_id++) {
115 if (tm_sched_bitset[sched_id] == 0) {
116 tm_sched_bitset[sched_id] = 1;
117 break;
118 }
119 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530120
121 if (sched_id < MAX_TM_SCHED_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530122 sched_map[key] = sched_id;
Girish Gowdra252f4972020-09-07 21:24:01 -0700123 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530124 return sched_id;
125 } else {
Girish Gowdra252f4972020-09-07 21:24:01 -0700126 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530127 return -1;
128 }
129}
130
131/**
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000132* 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 +0530133*
134* @param intf_id NNI or PON intf ID
135* @param onu_id ONU ID
136* @param uni_id UNI ID
137* @param gemport_id GEM Port ID
138* @param direction Upstream or downstream
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000139* @param tech_profile_id Technology Profile ID
Girish Gowdraddf9a162020-01-27 12:56:27 +0530140*/
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000141void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
142 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530143 std::map<sched_map_key_tuple, int>::const_iterator it;
Girish Gowdra252f4972020-09-07 21:24:01 -0700144 bcmos_fastlock_lock(&tm_sched_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530145 it = sched_map.find(key);
146 if (it != sched_map.end()) {
147 tm_sched_bitset[it->second] = 0;
148 sched_map.erase(it);
149 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700150 bcmos_fastlock_unlock(&tm_sched_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530151}
152
Burak Gurdag2f2618c2020-04-23 13:20:30 +0000153bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
154 sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530155 std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
156 if (it != sched_map.end()) {
157 return true;
158 }
159 return false;
160}
161
162/**
163* Check whether given two tm qmp profiles are equal or not
164*
165* @param tmq_map_profileA <vector> TM QUEUE MAPPING PROFILE
166* @param tmq_map_profileB <vector> TM QUEUE MAPPING PROFILE
167*
168* @return boolean, true if given tmq_map_profiles are equal else false
169*/
170
171bool check_tm_qmp_equality(std::vector<uint32_t> tmq_map_profileA, std::vector<uint32_t> tmq_map_profileB) {
172 for (uint32_t i = 0; i < TMQ_MAP_PROFILE_SIZE; i++) {
173 if (tmq_map_profileA[i] != tmq_map_profileB[i]) {
174 return false;
175 }
176 }
177 return true;
178}
179
180/**
181* Modifies given queues_pbit_map to parsable format
182* e.g: Modifes "0b00000101" to "10100000"
183*
184* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
185* @param size Queue count
186*
187* @return string queues_pbit_map
188*/
189std::string* get_valid_queues_pbit_map(std::string *queues_pbit_map, uint32_t size) {
190 for(uint32_t i=0; i < size; i++) {
191 /* Deletes 2 characters from index number 0 */
192 queues_pbit_map[i].erase(0, 2);
193 std::reverse(queues_pbit_map[i].begin(), queues_pbit_map[i].end());
194 }
195 return queues_pbit_map;
196}
197
198/**
199* Creates TM QUEUE MAPPING PROFILE for given queues_pbit_map and queues_priority_q
200*
201* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
202* @param queues_priority_q PRIORITY_Q configured for each GEM in TECH PROFILE
203* @param size Queue count
204*
205* @return <vector> TM QUEUE MAPPING PROFILE
206*/
207std::vector<uint32_t> get_tmq_map_profile(std::string *queues_pbit_map, uint32_t *queues_priority_q, uint32_t size) {
208 std::vector<uint32_t> tmq_map_profile(8,0);
209
210 for(uint32_t i=0; i < size; i++) {
211 for (uint32_t j = 0; j < queues_pbit_map[i].size(); j++) {
212 if (queues_pbit_map[i][j]=='1') {
213 tmq_map_profile.at(j) = queue_id_list[queues_priority_q[i]];
214 }
215 }
216 }
217 return tmq_map_profile;
218}
219
220/**
221* Gets corresponding tm_qmp_id for a given tmq_map_profile
222*
223* @param <vector> TM QUEUE MAPPING PROFILE
224*
225* @return tm_qmp_id
226*/
227int get_tm_qmp_id(std::vector<uint32_t> tmq_map_profile) {
228 int tm_qmp_id = -1;
229
230 std::map<int, std::vector < uint32_t > >::const_iterator it = qmp_id_to_qmp_map.begin();
231 while(it != qmp_id_to_qmp_map.end()) {
232 if(check_tm_qmp_equality(tmq_map_profile, it->second)) {
233 tm_qmp_id = it->first;
234 break;
235 }
236 it++;
237 }
238 return tm_qmp_id;
239}
240
241/**
242* Updates sched_qmp_id_map with given sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id
243*
244* @param upstream/downstream sched_id
245* @param PON intf ID
246* @param onu_id ONU ID
247* @param uni_id UNI ID
248* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
249*/
250void update_sched_qmp_id_map(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
251 uint32_t uni_id, int tm_qmp_id) {
Girish Gowdra252f4972020-09-07 21:24:01 -0700252 bcmos_fastlock_lock(&tm_qmp_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530253 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
254 sched_qmp_id_map.insert(make_pair(key, tm_qmp_id));
Girish Gowdra252f4972020-09-07 21:24:01 -0700255 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530256}
257
258/**
259* Gets corresponding tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
260*
261* @param upstream/downstream sched_id
262* @param PON intf ID
263* @param onu_id ONU ID
264* @param uni_id UNI ID
265*
266* @return tm_qmp_id
267*/
268int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
269 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
270 int tm_qmp_id = -1;
271
272 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
273 if (it != sched_qmp_id_map.end()) {
274 tm_qmp_id = it->second;
275 }
276 return tm_qmp_id;
277}
278
279/**
280* Gets a unique tm_qmp_id for a given tmq_map_profile
281* The tm_qmp_id is locally cached in a map, so that it can be rendered when necessary.
282* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
283*
284* @param upstream/downstream sched_id
285* @param PON intf ID
286* @param onu_id ONU ID
287* @param uni_id UNI ID
288* @param <vector> TM QUEUE MAPPING PROFILE
289*
290* @return tm_qmp_id
291*/
292int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, \
293 std::vector<uint32_t> tmq_map_profile) {
294 int tm_qmp_id;
295
Girish Gowdra252f4972020-09-07 21:24:01 -0700296 bcmos_fastlock_lock(&tm_qmp_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530297 /* Complexity of O(n). Is there better way that can avoid linear search? */
298 for (tm_qmp_id = 0; tm_qmp_id < MAX_TM_QMP_ID; tm_qmp_id++) {
299 if (tm_qmp_bitset[tm_qmp_id] == 0) {
300 tm_qmp_bitset[tm_qmp_id] = 1;
301 break;
302 }
303 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530304
305 if (tm_qmp_id < MAX_TM_QMP_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530306 qmp_id_to_qmp_map.insert(make_pair(tm_qmp_id, tmq_map_profile));
Girish Gowdra252f4972020-09-07 21:24:01 -0700307 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530308 update_sched_qmp_id_map(sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id);
309 return tm_qmp_id;
310 } else {
Girish Gowdra252f4972020-09-07 21:24:01 -0700311 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530312 return -1;
313 }
314}
315
316/**
317* Free tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
318*
319* @param upstream/downstream sched_id
320* @param PON intf ID
321* @param onu_id ONU ID
322* @param uni_id UNI ID
323* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
324*
325* @return boolean, true if no more reference for TM QMP else false
326*/
327bool free_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
328 uint32_t uni_id, int tm_qmp_id) {
329 bool result;
330 sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
331 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
Girish Gowdra252f4972020-09-07 21:24:01 -0700332 bcmos_fastlock_lock(&tm_qmp_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530333 if (it != sched_qmp_id_map.end()) {
334 sched_qmp_id_map.erase(it);
335 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530336
337 uint32_t tm_qmp_ref_count = 0;
338 std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it2 = sched_qmp_id_map.begin();
339 while(it2 != sched_qmp_id_map.end()) {
340 if(it2->second == tm_qmp_id) {
341 tm_qmp_ref_count++;
342 }
343 it2++;
344 }
345
346 if (tm_qmp_ref_count == 0) {
347 std::map<int, std::vector < uint32_t > >::const_iterator it3 = qmp_id_to_qmp_map.find(tm_qmp_id);
348 if (it3 != qmp_id_to_qmp_map.end()) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530349 tm_qmp_bitset[tm_qmp_id] = 0;
350 qmp_id_to_qmp_map.erase(it3);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530351 OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So clearing it\n", \
352 tm_qmp_id, tm_qmp_ref_count);
353 result = true;
354 }
355 } else {
356 OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So not clearing it\n", \
357 tm_qmp_id, tm_qmp_ref_count);
358 result = false;
359 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700360 bcmos_fastlock_unlock(&tm_qmp_bitset_lock, 0);
361
Girish Gowdraddf9a162020-01-27 12:56:27 +0530362 return result;
363}
364
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530365/* ACL ID is a shared resource, caller of this function has to ensure atomicity using locks
366 Gets free ACL ID if available, else -1. */
Girish Gowdraddf9a162020-01-27 12:56:27 +0530367int get_acl_id() {
368 int acl_id;
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530369
Girish Gowdra252f4972020-09-07 21:24:01 -0700370 bcmos_fastlock_lock(&acl_id_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530371 /* Complexity of O(n). Is there better way that can avoid linear search? */
372 for (acl_id = 0; acl_id < MAX_ACL_ID; acl_id++) {
373 if (acl_id_bitset[acl_id] == 0) {
374 acl_id_bitset[acl_id] = 1;
375 break;
376 }
377 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700378 bcmos_fastlock_unlock(&acl_id_bitset_lock, 0);
379
Girish Gowdraddf9a162020-01-27 12:56:27 +0530380 if (acl_id < MAX_ACL_ID) {
381 return acl_id ;
382 } else {
383 return -1;
384 }
385}
386
Thiyagarajan Subramani1744c922020-02-16 18:55:02 +0530387/* ACL ID is a shared resource, caller of this function has to ensure atomicity using locks
388 Frees up the ACL ID. */
Girish Gowdraddf9a162020-01-27 12:56:27 +0530389void free_acl_id (int acl_id) {
Girish Gowdra252f4972020-09-07 21:24:01 -0700390 bcmos_fastlock_lock(&acl_id_bitset_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530391 if (acl_id < MAX_ACL_ID) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530392 acl_id_bitset[acl_id] = 0;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530393 }
Girish Gowdra252f4972020-09-07 21:24:01 -0700394 bcmos_fastlock_unlock(&acl_id_bitset_lock, 0);
395}
396
397/* Gets a free Flow ID if available, else INVALID_FLOW_ID */
398uint16_t get_flow_id() {
399 uint16_t flow_id;
400
401 bcmos_fastlock_lock(&flow_id_bitset_lock);
402 /* Complexity of O(n). Is there better way that can avoid linear search? */
403 // start flow_id from 1 as 0 is invalid
404 for (flow_id = FLOW_ID_START; flow_id <= FLOW_ID_END; flow_id++) {
405 if (flow_id_bitset[flow_id] == 0) {
406 flow_id_bitset[flow_id] = 1;
407 break;
408 }
409 }
410 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
411
412 if (flow_id <= MAX_FLOW_ID) {
413 return flow_id ;
414 } else {
415 return INVALID_FLOW_ID;
416 }
417}
418
419/* Gets requested number of Flow IDs.
420 'num_of_flow_ids' is number of flow_ids requested. This cannot be more than NUMBER_OF_PBITS
421 'flow_ids' is pointer to array of size NUMBER_OF_PBITS
422 If the operation is successful, returns true else false
423 The operation is successful if we can allocate fully the number of flow_ids requested.
424 */
425bool get_flow_ids(int num_of_flow_ids, uint16_t *flow_ids) {
426 if (num_of_flow_ids > NUMBER_OF_PBITS) {
427 OPENOLT_LOG(ERROR, openolt_log_id, "requested number of flow_ids is more than 8\n");
428 return false;
429 }
430 int cnt = 0;
431
432 bcmos_fastlock_lock(&flow_id_bitset_lock);
433 /* Complexity of O(n). Is there better way that can avoid linear search? */
434 // start flow_id from 1 as 0 is invalid
435 for (uint16_t flow_id = FLOW_ID_START; flow_id <= FLOW_ID_END && cnt < num_of_flow_ids; flow_id++) {
436 if (flow_id_bitset[flow_id] == 0) {
437 flow_id_bitset[flow_id] = 1;
438 flow_ids[cnt] = flow_id;
439 cnt++;
440 }
441 }
442 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
443 // If we could not allocate the requested number of flow_ids free the allocated flow_ids
444 // and return false
445 if (cnt != num_of_flow_ids) {
446 OPENOLT_LOG(ERROR, openolt_log_id, "could not allocated the rquested number of flows ids. requested=%d, allocated=%d", num_of_flow_ids, cnt);
447 if (cnt > 0) {
448 for(int i=0; i < cnt; i++) {
449 free_flow_id(flow_ids[i]);
450 }
451 }
452 return false;
453 }
454 return true;
455}
456
457/* Frees up the FLOW ID. */
458void free_flow_id (uint16_t flow_id) {
459 bcmos_fastlock_lock(&flow_id_bitset_lock);
460 if (flow_id <= MAX_FLOW_ID) {
461 flow_id_bitset[flow_id] = 0;
462 }
463 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
464}
465
466void free_flow_ids(uint8_t num_flows, uint16_t *flow_ids) {
467 for (uint8_t i = 0; i < num_flows; i++) {
468 bcmos_fastlock_lock(&flow_id_bitset_lock);
469 if (flow_ids[i] <= MAX_FLOW_ID) {
470 flow_id_bitset[flow_ids[i]] = 0;
471 }
472 bcmos_fastlock_unlock(&flow_id_bitset_lock, 0);
473 }
Girish Gowdraddf9a162020-01-27 12:56:27 +0530474}
475
476/**
477* Returns qos type as string
478*
479* @param qos_type bcmolt_egress_qos_type enum
480*/
481std::string get_qos_type_as_string(bcmolt_egress_qos_type qos_type) {
482 switch (qos_type)
483 {
484 case BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE: return "FIXED_QUEUE";
485 case BCMOLT_EGRESS_QOS_TYPE_TC_TO_QUEUE: return "TC_TO_QUEUE";
486 case BCMOLT_EGRESS_QOS_TYPE_PBIT_TO_TC: return "PBIT_TO_TC";
487 case BCMOLT_EGRESS_QOS_TYPE_NONE: return "NONE";
488 case BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE: return "PRIORITY_TO_QUEUE";
489 default: OPENOLT_LOG(ERROR, openolt_log_id, "qos-type-not-supported %d\n", qos_type);
490 return "qos-type-not-supported";
491 }
492}
493
494/**
495* Gets/Updates qos type for given pon_intf_id, onu_id, uni_id
496*
497* @param PON intf ID
498* @param onu_id ONU ID
499* @param uni_id UNI ID
500* @param queue_size TrafficQueues Size
501*
502* @return qos_type
503*/
504bcmolt_egress_qos_type get_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, uint32_t queue_size) {
505 qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
506 bcmolt_egress_qos_type egress_qos_type = BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
507 std::string qos_string;
508
509 std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
510 if (it != qos_type_map.end()) {
511 egress_qos_type = it->second;
512 qos_string = get_qos_type_as_string(egress_qos_type);
513 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", \
514 pon_intf_id, onu_id, uni_id, qos_string.c_str());
515 }
516 else {
517 /* QOS Type has been pre-defined as Fixed Queue but it will be updated based on number of GEMPORTS
518 associated for a given subscriber. If GEM count = 1 for a given subscriber, qos_type will be Fixed Queue
519 else Priority to Queue */
520 egress_qos_type = (queue_size > 1) ? \
521 BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE : BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
522 bcmos_fastlock_lock(&data_lock);
523 qos_type_map.insert(make_pair(key, egress_qos_type));
524 bcmos_fastlock_unlock(&data_lock, 0);
525 qos_string = get_qos_type_as_string(egress_qos_type);
526 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", \
527 pon_intf_id, onu_id, uni_id, qos_string.c_str());
528 }
529 return egress_qos_type;
530}
531
532/**
533* Clears qos type for given pon_intf_id, onu_id, uni_id
534*
535* @param PON intf ID
536* @param onu_id ONU ID
537* @param uni_id UNI ID
538*/
539void clear_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
540 qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
541 std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
542 bcmos_fastlock_lock(&data_lock);
543 if (it != qos_type_map.end()) {
544 qos_type_map.erase(it);
545 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", \
546 pon_intf_id, onu_id, uni_id);
547 }
548 bcmos_fastlock_unlock(&data_lock, 0);
549}
550
551/**
552* Returns Scheduler/Queue direction as string
553*
554* @param direction as specified in tech_profile.proto
555*/
556std::string GetDirection(int direction) {
557 switch (direction)
558 {
559 case tech_profile::Direction::UPSTREAM: return upstream;
560 case tech_profile::Direction::DOWNSTREAM: return downstream;
561 default: OPENOLT_LOG(ERROR, openolt_log_id, "direction-not-supported %d\n", direction);
562 return "direction-not-supported";
563 }
564}
565
566// This method handles waiting for AllocObject configuration.
567// Returns error if the AllocObject is not in the appropriate state based on action requested.
568bcmos_errno wait_for_alloc_action(uint32_t intf_id, uint32_t alloc_id, AllocCfgAction action) {
569 Queue<alloc_cfg_complete_result> cfg_result;
570 alloc_cfg_compltd_key k(intf_id, alloc_id);
571 alloc_cfg_compltd_map[k] = &cfg_result;
572 bcmos_errno err = BCM_ERR_OK;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530573
574 // Try to pop the result from BAL with a timeout of ALLOC_CFG_COMPLETE_WAIT_TIMEOUT ms
575 std::pair<alloc_cfg_complete_result, bool> result = cfg_result.pop(ALLOC_CFG_COMPLETE_WAIT_TIMEOUT);
576 if (result.second == false) {
577 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for alloc cfg complete indication intf_id %d, alloc_id %d\n",
578 intf_id, alloc_id);
579 // Invalidate the queue pointer.
580 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
581 alloc_cfg_compltd_map[k] = NULL;
582 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
583 err = BCM_ERR_INTERNAL;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530584 }
585 else if (result.first.status == ALLOC_CFG_STATUS_FAIL) {
586 OPENOLT_LOG(ERROR, openolt_log_id, "error processing alloc cfg request intf_id %d, alloc_id %d\n",
587 intf_id, alloc_id);
588 err = BCM_ERR_INTERNAL;
589 }
590
591 if (err == BCM_ERR_OK) {
592 if (action == ALLOC_OBJECT_CREATE) {
593 if (result.first.state != ALLOC_OBJECT_STATE_ACTIVE) {
594 OPENOLT_LOG(ERROR, openolt_log_id, "alloc object not in active state intf_id %d, alloc_id %d alloc_obj_state %d\n",
595 intf_id, alloc_id, result.first.state);
596 err = BCM_ERR_INTERNAL;
597 } else {
598 OPENOLT_LOG(INFO, openolt_log_id, "Create upstream bandwidth allocation success, intf_id %d, alloc_id %d\n",
599 intf_id, alloc_id);
600 }
601 } else { // ALLOC_OBJECT_DELETE
602 if (result.first.state != ALLOC_OBJECT_STATE_NOT_CONFIGURED) {
603 OPENOLT_LOG(ERROR, openolt_log_id, "alloc object is not reset intf_id %d, alloc_id %d alloc_obj_state %d\n",
604 intf_id, alloc_id, result.first.state);
605 err = BCM_ERR_INTERNAL;
606 } else {
607 OPENOLT_LOG(INFO, openolt_log_id, "Remove alloc object success, intf_id %d, alloc_id %d\n",
608 intf_id, alloc_id);
609 }
610 }
611 }
612
613 // Remove entry from map
614 bcmos_fastlock_lock(&alloc_cfg_wait_lock);
615 alloc_cfg_compltd_map.erase(k);
616 bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
Girish Gowdra7a79dae2020-02-10 18:22:11 +0530617 return err;
618}
619
620// This method handles waiting for OnuDeactivate Completed Indication
621bcmos_errno wait_for_onu_deactivate_complete(uint32_t intf_id, uint32_t onu_id) {
622 Queue<onu_deactivate_complete_result> deact_result;
623 onu_deact_compltd_key k(intf_id, onu_id);
624 onu_deact_compltd_map[k] = &deact_result;
625 bcmos_errno err = BCM_ERR_OK;
626
627 // Try to pop the result from BAL with a timeout of ONU_DEACTIVATE_COMPLETE_WAIT_TIMEOUT ms
628 std::pair<onu_deactivate_complete_result, bool> result = deact_result.pop(ONU_DEACTIVATE_COMPLETE_WAIT_TIMEOUT);
629 if (result.second == false) {
630 OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for onu deactivate complete indication intf_id %d, onu_id %d\n",
631 intf_id, onu_id);
632 // Invalidate the queue pointer.
633 bcmos_fastlock_lock(&onu_deactivate_wait_lock);
634 onu_deact_compltd_map[k] = NULL;
635 bcmos_fastlock_unlock(&onu_deactivate_wait_lock, 0);
636 err = BCM_ERR_INTERNAL;
637 }
638 else if (result.first.result == BCMOLT_RESULT_FAIL) {
639 OPENOLT_LOG(ERROR, openolt_log_id, "error processing onu deactivate request intf_id %d, onu_id %d, fail_reason %d\n",
640 intf_id, onu_id, result.first.reason);
641 err = BCM_ERR_INTERNAL;
642 } else if (result.first.result == BCMOLT_RESULT_SUCCESS) {
643 OPENOLT_LOG(INFO, openolt_log_id, "success processing onu deactivate request intf_id %d, onu_id %d\n",
644 intf_id, onu_id);
645 }
646
647 // Remove entry from map
648 bcmos_fastlock_lock(&onu_deactivate_wait_lock);
649 onu_deact_compltd_map.erase(k);
650 bcmos_fastlock_unlock(&onu_deactivate_wait_lock, 0);
651
Girish Gowdraddf9a162020-01-27 12:56:27 +0530652 return err;
653}
654
655char* openolt_read_sysinfo(const char* field_name, char* field_val)
656{
657 FILE *fp;
658 /* Prepare the command*/
659 char command[150];
660
661 snprintf(command, sizeof command, "bash -l -c \"onlpdump -s\" | perl -ne 'print $1 if /%s: (\\S+)/'", field_name);
662 /* Open the command for reading. */
663 fp = popen(command, "r");
664 if (fp == NULL) {
665 /*The client has to check for a Null field value in this case*/
666 OPENOLT_LOG(INFO, openolt_log_id, "Failed to query the %s\n", field_name);
667 return field_val;
668 }
669
670 /*Read the field value*/
671 if (fp) {
672 uint8_t ret;
673 ret = fread(field_val, OPENOLT_FIELD_LEN, 1, fp);
674 if (ret >= OPENOLT_FIELD_LEN)
675 OPENOLT_LOG(INFO, openolt_log_id, "Read data length %u\n", ret);
676 pclose(fp);
677 }
678 return field_val;
679}
680
681Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state)
682{
Girish Gowdra252f4972020-09-07 21:24:01 -0700683 ::openolt::Indication ind;
684 ::openolt::IntfOperIndication* intf_oper_ind = new ::openolt::IntfOperIndication;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530685
686 intf_oper_ind->set_type(type);
687 intf_oper_ind->set_intf_id(intf_id);
688 intf_oper_ind->set_oper_state(state);
689 ind.set_allocated_intf_oper_ind(intf_oper_ind);
690 oltIndQ.push(ind);
691 return Status::OK;
692}
693
694#define CLI_HOST_PROMPT_FORMAT "BCM.%u> "
695
696/* Build CLI prompt */
697void openolt_cli_get_prompt_cb(bcmcli_session *session, char *buf, uint32_t max_len)
698{
699 snprintf(buf, max_len, CLI_HOST_PROMPT_FORMAT, dev_id);
700}
701
702int _bal_apiend_cli_thread_handler(long data)
703{
704 char init_string[]="\n";
705 bcmcli_session *sess = current_session;
706 bcmos_task_parm bal_cli_task_p_dummy;
707
708 /* Switch to interactive mode if not stopped in the init script */
709 if (!bcmcli_is_stopped(sess)) {
710 /* Force a CLI command prompt
711 * The string passed into the parse function
712 * must be modifiable, so a string constant like
713 * bcmcli_parse(current_session, "\n") will not
714 * work.
715 */
716 bcmcli_parse(sess, init_string);
717
718 /* Process user input until EOF or quit command */
719 bcmcli_driver(sess);
720 }
721 OPENOLT_LOG(INFO, openolt_log_id, "BAL API End CLI terminated\n");
722
723 /* Cleanup */
724 bcmcli_session_close(current_session);
725 bcmcli_token_destroy(NULL);
726 return 0;
727}
728
729/* Init API CLI commands for the current device */
730bcmos_errno bcm_openolt_api_cli_init(bcmcli_entry *parent_dir, bcmcli_session *session)
731{
732 bcmos_errno rc;
733
734 api_parent_dir = parent_dir;
735
736 rc = bcm_api_cli_set_commands(session);
737
738#ifdef BCM_SUBSYSTEM_HOST
739 /* Subscribe for device change indication */
740 rc = rc ? rc : bcmolt_olt_sel_ind_register(_api_cli_olt_change_ind);
741#endif
742
743 return rc;
744}
745
746bcmos_errno bcm_cli_quit(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
747{
748 bcmcli_stop(session);
749 bcmcli_session_print(session, "CLI terminated by 'Quit' command\n");
750 status_bcm_cli_quit = BCMOS_TRUE;
751
752 return BCM_ERR_OK;
753}
754
755int get_status_bcm_cli_quit(void) {
756 return status_bcm_cli_quit;
757}
758
759bcmos_errno bcmolt_apiend_cli_init() {
760 bcmos_errno ret;
761 bcmos_task_parm bal_cli_task_p = {};
762 bcmos_task_parm bal_cli_task_p_dummy;
763
764 /** before creating the task, check if it is already created by the other half of BAL i.e. Core side */
765 if (BCM_ERR_OK != bcmos_task_query(&bal_cli_thread, &bal_cli_task_p_dummy)) {
766 /* Create BAL CLI thread */
767 bal_cli_task_p.name = bal_cli_thread_name;
768 bal_cli_task_p.handler = _bal_apiend_cli_thread_handler;
769 bal_cli_task_p.priority = TASK_PRIORITY_CLI;
770
771 ret = bcmos_task_create(&bal_cli_thread, &bal_cli_task_p);
772 if (BCM_ERR_OK != ret) {
773 bcmos_printf("Couldn't create BAL API end CLI thread\n");
774 return ret;
775 }
776 }
777}
778
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530779bcmos_errno get_onu_status(bcmolt_interface pon_ni, int onu_id, bcmolt_onu_state *onu_state) {
780 bcmos_errno err;
781 bcmolt_onu_cfg onu_cfg;
782 bcmolt_onu_key onu_key;
783 onu_key.pon_ni = pon_ni;
784 onu_key.onu_id = onu_id;
785
786 BCMOLT_CFG_INIT(&onu_cfg, onu, onu_key);
787 BCMOLT_FIELD_SET_PRESENT(&onu_cfg.data, onu_cfg_data, onu_state);
788 BCMOLT_FIELD_SET_PRESENT(&onu_cfg.data, onu_cfg_data, itu);
789 #ifdef TEST_MODE
790 // It is impossible to mock the setting of onu_cfg.data.onu_state because
791 // the actual bcmolt_cfg_get passes the address of onu_cfg.hdr and we cannot
792 // set the onu_cfg.data.onu_state. So a new stub function is created and address
793 // of onu_cfg is passed. This is one-of case where we need to add test specific
794 // code in production code.
795 err = bcmolt_cfg_get__onu_state_stub(dev_id, &onu_cfg);
796 #else
797 err = bcmolt_cfg_get(dev_id, &onu_cfg.hdr);
798 #endif
799 *onu_state = onu_cfg.data.onu_state;
800 return err;
801}
802
803bcmos_errno get_pon_interface_status(bcmolt_interface pon_ni, bcmolt_interface_state *state, bcmolt_status *los_status) {
Girish Gowdraddf9a162020-01-27 12:56:27 +0530804 bcmos_errno err;
805 bcmolt_pon_interface_key pon_key;
806 bcmolt_pon_interface_cfg pon_cfg;
807 pon_key.pon_ni = pon_ni;
808
809 BCMOLT_CFG_INIT(&pon_cfg, pon_interface, pon_key);
810 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, state);
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530811 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, los_status);
Girish Gowdraddf9a162020-01-27 12:56:27 +0530812 BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, itu);
813 #ifdef TEST_MODE
814 // It is impossible to mock the setting of pon_cfg.data.state because
815 // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
816 // set the pon_cfg.data.state. So a new stub function is created and address
817 // of pon_cfg is passed. This is one-of case where we need to add test specific
818 // code in production code.
819 err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
820 #else
821 err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
822 #endif
823 *state = pon_cfg.data.state;
Thiyagarajan Subramaniad463232020-02-28 19:10:43 +0530824 *los_status = pon_cfg.data.los_status;
Girish Gowdraddf9a162020-01-27 12:56:27 +0530825 return err;
826}
827
828/* Same as bcmolt_cfg_get but with added logic of retrying the API
829 in case of some specific failures like timeout or object not yet ready
830*/
831bcmos_errno bcmolt_cfg_get_mult_retry(bcmolt_oltid olt, bcmolt_cfg *cfg) {
832 bcmos_errno err;
833 uint32_t current_try = 0;
834
835 while (current_try < MAX_BAL_API_RETRY_COUNT) {
836 err = bcmolt_cfg_get(olt, cfg);
837 current_try++;
838
839 if (err == BCM_ERR_STATE || err == BCM_ERR_TIMEOUT) {
840 OPENOLT_LOG(WARNING, openolt_log_id, "bcmolt_cfg_get: err = %s\n", bcmos_strerror(err));
841 bcmos_usleep(BAL_API_RETRY_TIME_IN_USECS);
842 continue;
843 }
844 else {
845 break;
846 }
847 }
848
849 if (err != BCM_ERR_OK) {
850 OPENOLT_LOG(ERROR, openolt_log_id, "bcmolt_cfg_get tried (%d) times with retry time(%d usecs) err = %s\n",
851 current_try,
852 BAL_API_RETRY_TIME_IN_USECS,
853 bcmos_strerror(err));
854 }
855 return err;
856}
857
858
859unsigned NumNniIf_() {return num_of_nni_ports;}
860unsigned NumPonIf_() {return num_of_pon_ports;}
861
862bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state) {
863 bcmos_errno err;
864 bcmolt_nni_interface_key nni_key;
865 bcmolt_nni_interface_cfg nni_cfg;
866 nni_key.id = id;
867
868 BCMOLT_CFG_INIT(&nni_cfg, nni_interface, nni_key);
869 BCMOLT_FIELD_SET_PRESENT(&nni_cfg.data, nni_interface_cfg_data, state);
870 #ifdef TEST_MODE
871 // It is impossible to mock the setting of nni_cfg.data.state because
872 // the actual bcmolt_cfg_get passes the address of nni_cfg.hdr and we cannot
873 // set the nni_cfg.data.state. So a new stub function is created and address
874 // of nni_cfg is passed. This is one-of case where we need to add test specific
875 // code in production code.
876 err = bcmolt_cfg_get__nni_intf_stub(dev_id, &nni_cfg);
877 #else
878 err = bcmolt_cfg_get(dev_id, &nni_cfg.hdr);
879 #endif
880 *state = nni_cfg.data.state;
881 return err;
882}
883
884Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t gemport_id) {
885 bcmos_errno err;
886 bcmolt_itupon_gem_cfg cfg; /* declare main API struct */
887 bcmolt_itupon_gem_key key = {}; /* declare key */
888 bcmolt_gem_port_configuration configuration = {};
889
890 key.pon_ni = intf_id;
891 key.gem_port_id = gemport_id;
892
893 BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
894
895 bcmolt_gem_port_direction configuration_direction;
896 configuration_direction = BCMOLT_GEM_PORT_DIRECTION_BIDIRECTIONAL;
897 BCMOLT_FIELD_SET(&configuration, gem_port_configuration, direction, configuration_direction);
898
899 bcmolt_gem_port_type configuration_type;
900 configuration_type = BCMOLT_GEM_PORT_TYPE_UNICAST;
901 BCMOLT_FIELD_SET(&configuration, gem_port_configuration, type, configuration_type);
902
903 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, configuration, configuration);
904
905 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, onu_id, onu_id);
906
907 bcmolt_control_state encryption_mode;
908 encryption_mode = BCMOLT_CONTROL_STATE_DISABLE;
909 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
910
911 bcmolt_us_gem_port_destination upstream_destination_queue;
912 upstream_destination_queue = BCMOLT_US_GEM_PORT_DESTINATION_DATA;
913 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, upstream_destination_queue, upstream_destination_queue);
914
915 bcmolt_control_state control;
916 control = BCMOLT_CONTROL_STATE_ENABLE;
917 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, control, control);
918
919 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
920 if(err != BCM_ERR_OK) {
Burak Gurdaga0523592021-02-24 15:17:47 +0000921 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 +0530922 return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
923 }
924
925 OPENOLT_LOG(INFO, openolt_log_id, "gem port installed successfully = %d\n", gemport_id);
926
927 return Status::OK;
928}
929
930Status remove_gem_port(int32_t intf_id, int32_t gemport_id) {
931 bcmolt_itupon_gem_cfg gem_cfg;
932 bcmolt_itupon_gem_key key = {
933 .pon_ni = (bcmolt_interface)intf_id,
934 .gem_port_id = (bcmolt_gem_port_id)gemport_id
935 };
936 bcmos_errno err;
937
938 BCMOLT_CFG_INIT(&gem_cfg, itupon_gem, key);
939 err = bcmolt_cfg_clear(dev_id, &gem_cfg.hdr);
940 if (err != BCM_ERR_OK)
941 {
Burak Gurdaga0523592021-02-24 15:17:47 +0000942 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 +0530943 return bcm_to_grpc_err(err, "Access_Control clear ITU PON Gem port failed");
944 }
945
946 OPENOLT_LOG(INFO, openolt_log_id, "gem port removed successfully = %d\n", gemport_id);
947
948 return Status::OK;
949}
950
Burak Gurdaga0523592021-02-24 15:17:47 +0000951Status enable_encryption_for_gem_port(int32_t intf_id, int32_t gemport_id) {
952 bcmos_errno err;
953 bcmolt_itupon_gem_cfg cfg;
954 bcmolt_itupon_gem_key key = {
955 .pon_ni = (bcmolt_interface)intf_id,
956 .gem_port_id = (bcmolt_gem_port_id)gemport_id
957 };
958
959 BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
960
961 bcmolt_control_state encryption_mode;
962 encryption_mode = BCMOLT_CONTROL_STATE_ENABLE;
963 BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
964
965 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
966 if(err != BCM_ERR_OK) {
967 OPENOLT_LOG(ERROR, openolt_log_id, "failed to set encryption on pon = %d gem_port = %d, err = %s (%d)\n",
968 intf_id, gemport_id, cfg.hdr.hdr.err_text, err);
969 return bcm_to_grpc_err(err, "Failed to set encryption on GEM port");;
970 }
971
972 OPENOLT_LOG(INFO, openolt_log_id, "encryption set successfully on pon = %d gem_port = %d\n", intf_id, gemport_id);
973
974 return Status::OK;
975}
976
Girish Gowdraddf9a162020-01-27 12:56:27 +0530977Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
978 bcmolt_members_update_command acl_cmd) {
979 bcmos_errno err;
980 bcmolt_access_control_interfaces_update oper; /* declare main API struct */
981 bcmolt_access_control_key acl_key = {}; /* declare key */
982 bcmolt_intf_ref interface_ref_list_elem = {};
983 bcmolt_interface_type interface_ref_list_elem_intf_type;
984 bcmolt_interface_id interface_ref_list_elem_intf_id;
985 bcmolt_intf_ref_list_u8 interface_ref_list = {};
986
987 if (acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_ADD && acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) {
988 OPENOLT_LOG(ERROR, openolt_log_id, "acl cmd = %d not supported currently\n", acl_cmd);
989 return bcm_to_grpc_err(BCM_ERR_PARM, "unsupported acl cmd");
990 }
991 interface_ref_list.arr = (bcmolt_intf_ref*)bcmos_calloc(sizeof(bcmolt_intf_ref)*1);
992
993 if (interface_ref_list.arr == NULL)
994 return bcm_to_grpc_err(BCM_ERR_PARM, "allocate interface_ref_list failed");
995 OPENOLT_LOG(INFO, openolt_log_id, "update acl interface received for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
996 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
997 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
998
999 acl_key.id = access_control_id;
1000
1001 /* Initialize the API struct. */
1002 BCMOLT_OPER_INIT(&oper, access_control, interfaces_update, acl_key);
1003
1004 bcmolt_members_update_command command;
1005 command = acl_cmd;
1006 BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, command, command);
1007
1008 interface_ref_list_elem_intf_type = intf_type;
1009 BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_type, interface_ref_list_elem_intf_type);
1010
1011 interface_ref_list_elem_intf_id = intf_id;
1012 BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_id, interface_ref_list_elem_intf_id);
1013
1014 interface_ref_list.len = 1;
1015 BCMOLT_ARRAY_ELEM_SET(&interface_ref_list, 0, interface_ref_list_elem);
1016
1017 BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, interface_ref_list, interface_ref_list);
1018
1019 err = bcmolt_oper_submit(dev_id, &oper.hdr);
1020 if (err != BCM_ERR_OK) {
1021 OPENOLT_LOG(ERROR, openolt_log_id, "update acl interface fail for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
1022 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
1023 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
1024 return bcm_to_grpc_err(err, "Access_Control submit interface failed");
1025 }
1026
1027 bcmos_free(interface_ref_list.arr);
1028 OPENOLT_LOG(INFO, openolt_log_id, "update acl interface success for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
1029 intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
1030 acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
1031
1032 return Status::OK;
1033}
1034
1035Status install_acl(const acl_classifier_key acl_key) {
Girish Gowdraddf9a162020-01-27 12:56:27 +05301036 bcmos_errno err;
1037 bcmolt_access_control_cfg cfg;
1038 bcmolt_access_control_key key = { };
1039 bcmolt_classifier c_val = { };
1040 // hardcode the action for now.
1041 bcmolt_access_control_fwd_action_type action_type = BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST;
Girish Gowdraddf9a162020-01-27 12:56:27 +05301042 int acl_id = get_acl_id();
1043 if (acl_id < 0) {
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001044 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",
1045 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 +05301046 return bcm_to_grpc_err(BCM_ERR_INTERNAL, "exhausted acl id");
1047 }
1048
1049 key.id = acl_id;
1050 /* config access control instance */
1051 BCMOLT_CFG_INIT(&cfg, access_control, key);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301052 if (acl_key.ether_type > 0) {
1053 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ether_type 0x%04x\n", acl_key.ether_type);
1054 BCMOLT_FIELD_SET(&c_val, classifier, ether_type, acl_key.ether_type);
1055 }
1056
1057 if (acl_key.ip_proto > 0) {
1058 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ip_proto %d\n", acl_key.ip_proto);
1059 BCMOLT_FIELD_SET(&c_val, classifier, ip_proto, acl_key.ip_proto);
1060 }
1061
1062 if (acl_key.dst_port > 0) {
1063 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify dst_port %d\n", acl_key.dst_port);
1064 BCMOLT_FIELD_SET(&c_val, classifier, dst_port, acl_key.dst_port);
1065 }
1066
1067 if (acl_key.src_port > 0) {
1068 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify src_port %d\n", acl_key.src_port);
1069 BCMOLT_FIELD_SET(&c_val, classifier, src_port, acl_key.src_port);
1070 }
1071
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001072 // Make sure that max_acls_with_vlan_classifiers_hit is not true to consider o_vid for ACL classification.
1073 if (acl_key.o_vid > 0 && acl_key.o_vid != ANY_VLAN && !max_acls_with_vlan_classifiers_hit) {
1074 OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify o_vid %d\n", acl_key.o_vid);
1075 BCMOLT_FIELD_SET(&c_val, classifier, o_vid, acl_key.o_vid);
1076 }
1077
Girish Gowdraddf9a162020-01-27 12:56:27 +05301078 BCMOLT_MSG_FIELD_SET(&cfg, classifier, c_val);
1079 BCMOLT_MSG_FIELD_SET(&cfg, priority, 10000);
1080 BCMOLT_MSG_FIELD_SET(&cfg, statistics_control, BCMOLT_CONTROL_STATE_ENABLE);
1081
1082 BCMOLT_MSG_FIELD_SET(&cfg, forwarding_action.action, action_type);
1083
1084 err = bcmolt_cfg_set(dev_id, &cfg.hdr);
1085 if (err != BCM_ERR_OK) {
1086 OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control set configuration failed, Error %d\n", err);
1087 // Free the acl_id
1088 free_acl_id(acl_id);
1089 return bcm_to_grpc_err(err, "Access_Control set configuration failed");
1090 }
1091
1092 ACL_LOG(INFO, "ACL add ok", err);
1093
1094 // Update the map that we have installed an acl for the given classfier.
1095 acl_classifier_to_acl_id_map[acl_key] = acl_id;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001096 // 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
1097 // After max_acls_with_vlan_classifiers_hit is set to true no more ACLs can have vlan as an ACL classifier.
1098 if (acl_key.o_vid > 0 && acl_key.o_vid != ANY_VLAN && acl_id >= MAX_ACL_WITH_VLAN_CLASSIFIER) {
1099 max_acls_with_vlan_classifiers_hit = true;
1100 }
Girish Gowdraddf9a162020-01-27 12:56:27 +05301101 return Status::OK;
1102}
1103
1104Status remove_acl(int acl_id) {
1105 bcmos_errno err;
1106 bcmolt_access_control_cfg cfg; /* declare main API struct */
1107 bcmolt_access_control_key key = {}; /* declare key */
1108
1109 key.id = acl_id;
1110
1111 /* Initialize the API struct. */
1112 BCMOLT_CFG_INIT(&cfg, access_control, key);
1113 BCMOLT_FIELD_SET_PRESENT(&cfg.data, access_control_cfg_data, state);
1114 err = bcmolt_cfg_get(dev_id, &cfg.hdr);
1115 if (err != BCM_ERR_OK) {
1116 OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control get state failed\n");
1117 return bcm_to_grpc_err(err, "Access_Control get state failed");
1118 }
1119
1120 if (cfg.data.state == BCMOLT_CONFIG_STATE_CONFIGURED) {
1121 key.id = acl_id;
1122 /* Initialize the API struct. */
1123 BCMOLT_CFG_INIT(&cfg, access_control, key);
1124
1125 err = bcmolt_cfg_clear(dev_id, &cfg.hdr);
1126 if (err != BCM_ERR_OK) {
1127 // Should we free acl_id here ? We should ideally never land here..
1128 OPENOLT_LOG(ERROR, openolt_log_id, "Error %d while removing Access_Control rule ID %d\n",
1129 err, acl_id);
1130 return Status(grpc::StatusCode::INTERNAL, "Failed to remove Access_Control");
1131 }
1132 }
1133
1134 // Free up acl_id
1135 free_acl_id(acl_id);
1136
1137 OPENOLT_LOG(INFO, openolt_log_id, "acl removed successfully %d\n", acl_id);
1138
1139 return Status::OK;
1140}
1141
1142// Formulates ACL Classifier Key based on the following fields
1143// a. ether_type b. ip_proto c. src_port d. dst_port
1144// If any of the field is not available it is populated as -1.
1145void formulate_acl_classifier_key(acl_classifier_key *key, const ::openolt::Classifier& classifier) {
1146
1147 // TODO: Is 0 a valid value for any of the following classifiers?
1148 // because in the that case, the 'if' check would fail and -1 would be filled as value.
1149 //
1150 if (classifier.eth_type()) {
1151 OPENOLT_LOG(DEBUG, openolt_log_id, "classify ether_type 0x%04x\n", classifier.eth_type());
1152 key->ether_type = classifier.eth_type();
1153 } else key->ether_type = -1;
1154
1155 if (classifier.ip_proto()) {
1156 OPENOLT_LOG(DEBUG, openolt_log_id, "classify ip_proto %d\n", classifier.ip_proto());
1157 key->ip_proto = classifier.ip_proto();
1158 } else key->ip_proto = -1;
1159
1160
1161 if (classifier.src_port()) {
1162 OPENOLT_LOG(DEBUG, openolt_log_id, "classify src_port %d\n", classifier.src_port());
1163 key->src_port = classifier.src_port();
1164 } else key->src_port = -1;
1165
1166
1167 if (classifier.dst_port()) {
1168 OPENOLT_LOG(DEBUG, openolt_log_id, "classify dst_port %d\n", classifier.dst_port());
1169 key->dst_port = classifier.dst_port();
1170 } else key->dst_port = -1;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001171
1172 // We should also check the max_acls_with_vlan_classifiers_hit flag is not false to consider the vlan for flow classifier key
1173 if (classifier.o_vid() && !max_acls_with_vlan_classifiers_hit) {
1174 OPENOLT_LOG(DEBUG, openolt_log_id, "classify o_vid %d\n", classifier.o_vid());
1175 key->o_vid = classifier.o_vid();
1176 } else key->o_vid = ANY_VLAN;
1177
Girish Gowdraddf9a162020-01-27 12:56:27 +05301178}
1179
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001180Status handle_acl_rule_install(int32_t onu_id, uint64_t flow_id, int32_t gemport_id,
Girish Gowdraddf9a162020-01-27 12:56:27 +05301181 const std::string flow_type, int32_t access_intf_id,
Girish Gowdra252f4972020-09-07 21:24:01 -07001182 int32_t network_intf_id,
Girish Gowdraddf9a162020-01-27 12:56:27 +05301183 const ::openolt::Classifier& classifier) {
1184 int acl_id;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001185 uint32_t intf_id = flow_type.compare(upstream) == 0? access_intf_id: network_intf_id;
Girish Gowdraddf9a162020-01-27 12:56:27 +05301186 const std::string intf_type = flow_type.compare(upstream) == 0? "pon": "nni";
1187 bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
1188
1189 Status resp;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001190 trap_to_host_packet_type pkt_type = get_trap_to_host_packet_type(classifier);
1191 if (pkt_type == unsupported_trap_to_host_pkt_type) {
1192 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported pkt trap type");
1193 return Status(grpc::StatusCode::UNIMPLEMENTED, "unsupported pkt trap type");
1194 }
Girish Gowdraddf9a162020-01-27 12:56:27 +05301195
1196 // few map keys we are going to use later.
1197 flow_id_flow_direction fl_id_fl_dir(flow_id, flow_type);
Girish Gowdra252f4972020-09-07 21:24:01 -07001198
Girish Gowdraddf9a162020-01-27 12:56:27 +05301199 acl_classifier_key acl_key;
1200 formulate_acl_classifier_key(&acl_key, classifier);
1201 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 -07001202 .src_port=acl_key.src_port, .dst_port=acl_key.dst_port, .o_vid=acl_key.o_vid};
1203 bcmos_fastlock_lock(&acl_packet_trap_handler_lock);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301204
1205 // Check if the acl is already installed
1206 if (acl_classifier_to_acl_id_map.count(acl_key_const) > 0) {
1207 // retreive the acl_id
1208 acl_id = acl_classifier_to_acl_id_map[acl_key_const];
Girish Gowdra252f4972020-09-07 21:24:01 -07001209
1210
Girish Gowdraddf9a162020-01-27 12:56:27 +05301211 if (flow_to_acl_map.count(fl_id_fl_dir)) {
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001212 // could happen if same trap flow is received again
Girish Gowdraddf9a162020-01-27 12:56:27 +05301213 OPENOLT_LOG(INFO, openolt_log_id, "flow and related acl already handled, nothing more to do\n");
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001214 bcmos_fastlock_unlock(&acl_packet_trap_handler_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301215 return Status::OK;
1216 }
1217
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001218 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",
1219 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 +05301220
1221 // The acl_ref_cnt is needed to know how many flows refer an ACL.
1222 // When the flow is removed, we decrement the reference count.
1223 // When the reference count becomes 0, we remove the ACL.
1224 if (acl_ref_cnt.count(acl_id) > 0) {
1225 acl_ref_cnt[acl_id] ++;
1226 } else {
1227 // We should ideally not land here. The acl_ref_cnt should have been
1228 // initialized the first time acl was installed.
1229 acl_ref_cnt[acl_id] = 1;
1230 }
1231
1232 } else {
1233 resp = install_acl(acl_key_const);
1234 if (!resp.ok()) {
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001235 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",
1236 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);
1237 bcmos_fastlock_unlock(&acl_packet_trap_handler_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301238 return resp;
1239 }
1240
1241 acl_id = acl_classifier_to_acl_id_map[acl_key_const];
1242
1243 // Initialize the acl reference count
1244 acl_ref_cnt[acl_id] = 1;
1245
Girish Gowdra252f4972020-09-07 21:24:01 -07001246 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 +05301247 }
1248
1249 // Register the interface for the given acl
1250 acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
1251 // This is needed to keep a track of which interface (pon/nni) has registered for an ACL.
1252 // If it is registered, how many flows refer to it.
1253 if (intf_acl_registration_ref_cnt.count(ac_id_inf_id_inf_type) > 0) {
1254 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]++;
1255 } else {
1256 // The given interface is not registered for the ACL. We need to do it now.
1257 resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_ADD);
1258 if (!resp.ok()){
1259 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);
1260 // TODO: Ideally we should return error from hear and clean up other other stateful
1261 // counters we creaed earlier. Will leave it out for now.
Girish Gowdra252f4972020-09-07 21:24:01 -07001262 }
Girish Gowdraddf9a162020-01-27 12:56:27 +05301263 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] = 1;
1264 }
1265
Girish Gowdra252f4972020-09-07 21:24:01 -07001266 acl_id_intf_id ac_id_if_id(acl_id, intf_id);
1267 flow_to_acl_map[fl_id_fl_dir] = ac_id_if_id;
Girish Gowdraddf9a162020-01-27 12:56:27 +05301268
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001269 // Populate the trap_to_host_pkt_info_with_vlan corresponding to the trap-to-host voltha flow_id key.
1270 // When the trap-to-host voltha flow-id is being removed, this entry is cleared too from the map.
1271 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());
1272 trap_to_host_pkt_info_with_vlan_for_flow_id[flow_id] = pkt_info_with_vlan;
1273 trap_to_host_pkt_info pkt_info((int32_t)olt_if_type, intf_id, (int32_t)pkt_type, gemport_id);
1274 bool duplicate = false;
1275 // Check if the vlan_id corresponding to the trap_to_host_pkt_info key is found. Set the 'duplicate' flag accordingly.
1276 if (trap_to_host_vlan_ids_for_trap_to_host_pkt_info.count(pkt_info) > 0) {
1277 auto& vlan_id_list = trap_to_host_vlan_ids_for_trap_to_host_pkt_info[pkt_info];
1278 auto it = std::find(vlan_id_list.begin(), vlan_id_list.end(), acl_key.o_vid);
1279 if (it != vlan_id_list.end()) {
1280 OPENOLT_LOG(DEBUG, openolt_log_id, "cvid = %d exists already in list", acl_key.o_vid);
1281 duplicate = true;
1282 }
1283 }
1284 // If the vlan_id is not found corresponding to the trap_to_host_pkt_info key, update it.
1285 // This will be used to validate the vlan_id in the trapped packet. If vlan_id in the
1286 // trapped packet is not match with the stored value, packet is dropped.
1287 if (!duplicate) {
1288 trap_to_host_vlan_ids_for_trap_to_host_pkt_info[pkt_info].push_back(acl_key.o_vid);
1289 }
1290
1291 bcmos_fastlock_unlock(&acl_packet_trap_handler_lock, 0);
Girish Gowdraddf9a162020-01-27 12:56:27 +05301292
1293 return Status::OK;
1294}
1295
Girish Gowdra252f4972020-09-07 21:24:01 -07001296Status handle_acl_rule_cleanup(int16_t acl_id, int32_t intf_id, const std::string flow_type) {
Girish Gowdraddf9a162020-01-27 12:56:27 +05301297 const std::string intf_type= flow_type.compare(upstream) == 0 ? "pon": "nni";
1298 acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
1299 intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]--;
1300 if (intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] == 0) {
1301 bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
1302 Status resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE);
1303 if (!resp.ok()){
1304 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);
1305 }
1306 intf_acl_registration_ref_cnt.erase(ac_id_inf_id_inf_type);
1307 }
1308
1309 acl_ref_cnt[acl_id]--;
1310 if (acl_ref_cnt[acl_id] == 0) {
1311 remove_acl(acl_id);
1312 acl_ref_cnt.erase(acl_id);
1313 // Iterate acl_classifier_to_acl_id_map and delete classifier the key corresponding to acl_id
1314 std::map<acl_classifier_key, uint16_t>::iterator it;
1315 for (it=acl_classifier_to_acl_id_map.begin(); it!=acl_classifier_to_acl_id_map.end(); ++it) {
1316 if (it->second == acl_id) {
1317 OPENOLT_LOG(INFO, openolt_log_id, "cleared classifier key corresponding to acl_id = %d\n", acl_id);
1318 acl_classifier_to_acl_id_map.erase(it->first);
1319 break;
1320 }
1321 }
1322 }
1323
Girish Gowdraddf9a162020-01-27 12:56:27 +05301324 return Status::OK;
1325}
1326
1327Status check_bal_ready() {
1328 bcmos_errno err;
1329 int maxTrials = 30;
1330 bcmolt_olt_cfg olt_cfg = { };
1331 bcmolt_olt_key olt_key = { };
1332
1333 BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
1334 BCMOLT_MSG_FIELD_GET(&olt_cfg, bal_state);
1335
1336 while (olt_cfg.data.bal_state != BCMOLT_BAL_STATE_BAL_AND_SWITCH_READY) {
1337 if (--maxTrials == 0)
1338 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check bal ready failed");
1339 sleep(5);
1340 #ifdef TEST_MODE
1341 // It is impossible to mock the setting of olt_cfg.data.bal_state because
1342 // the actual bcmolt_cfg_get passes the address of olt_cfg.hdr and we cannot
1343 // set the olt_cfg.data.bal_state. So a new stub function is created and address
1344 // of olt_cfg is passed. This is one-of case where we need to add test specific
1345 // code in production code.
1346 if (bcmolt_cfg_get__bal_state_stub(dev_id, &olt_cfg)) {
1347 #else
1348 if (bcmolt_cfg_get(dev_id, &olt_cfg.hdr)) {
1349 #endif
1350 continue;
1351 }
1352 else
1353 OPENOLT_LOG(INFO, openolt_log_id, "waiting for BAL ready ...\n");
1354 }
1355
1356 OPENOLT_LOG(INFO, openolt_log_id, "BAL is ready\n");
1357 return Status::OK;
1358}
1359
1360Status check_connection() {
1361 int maxTrials = 60;
1362 while (!bcmolt_api_conn_mgr_is_connected(dev_id)) {
1363 sleep(1);
1364 if (--maxTrials == 0)
1365 return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check connection failed");
1366 else
1367 OPENOLT_LOG(INFO, openolt_log_id, "waiting for daemon connection ...\n");
1368 }
1369 OPENOLT_LOG(INFO, openolt_log_id, "daemon is connected\n");
1370 return Status::OK;
1371}
1372
Thiyagarajan Subramani03bc66f2020-04-01 15:58:53 +05301373std::string get_ip_address(const char* nw_intf){
1374 std::string ipAddress = "0.0.0.0";
1375 struct ifaddrs *interfaces = NULL;
1376 struct ifaddrs *temp_addr = NULL;
1377 int success = 0;
1378 /* retrieve the current interfaces - returns 0 on success */
1379 success = getifaddrs(&interfaces);
1380 if (success == 0) {
1381 /* Loop through linked list of interfaces */
1382 temp_addr = interfaces;
1383 while(temp_addr != NULL) {
1384 if(temp_addr->ifa_addr->sa_family == AF_INET) {
1385 /* Check if interface given present in OLT, if yes return its IP Address */
1386 if(strcmp(temp_addr->ifa_name, nw_intf) == 0){
1387 ipAddress=inet_ntoa(((struct sockaddr_in*)temp_addr->ifa_addr)->sin_addr);
1388 break;
1389 }
1390 }
1391 temp_addr = temp_addr->ifa_next;
1392 }
1393 }
1394 /* Free memory */
1395 freeifaddrs(interfaces);
1396 return ipAddress;
1397}
Jason Huang1d9cfce2020-05-20 22:58:47 +08001398
1399bcmos_errno getOnuMaxLogicalDistance(uint32_t intf_id, uint32_t *mld) {
1400 bcmos_errno err = BCM_ERR_OK;
1401 bcmolt_pon_distance pon_distance = {};
1402 bcmolt_pon_interface_cfg pon_cfg; /* declare main API struct */
1403 bcmolt_pon_interface_key key = {}; /* declare key */
1404
1405 key.pon_ni = intf_id;
1406
1407 if (!state.is_activated()) {
1408 OPENOLT_LOG(ERROR, openolt_log_id, "ONU maximum logical distance is not available since OLT is not activated yet\n");
1409 return BCM_ERR_STATE;
1410 }
1411
1412 /* Initialize the API struct. */
1413 BCMOLT_CFG_INIT(&pon_cfg, pon_interface, key);
1414 BCMOLT_FIELD_SET_PRESENT(&pon_distance, pon_distance, max_log_distance);
1415 BCMOLT_FIELD_SET(&pon_cfg.data, pon_interface_cfg_data, pon_distance, pon_distance);
1416 #ifdef TEST_MODE
1417 // It is impossible to mock the setting of pon_cfg.data.state because
1418 // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
1419 // set the pon_cfg.data.state. So a new stub function is created and address
1420 // of pon_cfg is passed. This is one-of case where we need to add test specific
1421 // code in production code.
1422 err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
1423 #else
1424 err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
1425 #endif
1426 if (err != BCM_ERR_OK) {
1427 OPENOLT_LOG(ERROR, openolt_log_id, "Failed to retrieve ONU maximum logical distance for PON %d, err = %s (%d)\n", intf_id, bcmos_strerror(err), err);
1428 return err;
1429 }
1430 *mld = pon_distance.max_log_distance;
1431
1432 return BCM_ERR_OK;
1433}
Humera Kouser6143c9e2020-06-17 22:37:31 +05301434
1435/**
1436* Gets mac address based on interface name.
1437*
1438* @param intf_name interface name
1439* @param mac_address mac address field
1440* @param max_size_of_mac_address max sixe of the mac_address
1441* @return mac_address value in case of success or return NULL in case of failure.
1442*/
1443
1444char* get_intf_mac(const char* intf_name, char* mac_address, unsigned int max_size_of_mac_address){
1445 int fd;
1446 struct ifreq ifr;
1447 char *mac;
1448
1449 fd = socket(AF_INET, SOCK_DGRAM, 0);
1450 if ( fd == -1) {
1451 OPENOLT_LOG(ERROR, openolt_log_id, "failed to get mac, could not create file descriptor");
1452 return NULL;
1453 }
1454
1455 ifr.ifr_addr.sa_family = AF_INET;
1456 strncpy((char *)ifr.ifr_name , (const char *)intf_name , IFNAMSIZ-1);
1457 if( ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
1458 {
1459 OPENOLT_LOG(ERROR, openolt_log_id, "failed to get mac, ioctl failed and returned err");
1460 close(fd);
1461 return NULL;
1462 }
1463
1464 close(fd);
1465 mac = (char *)ifr.ifr_hwaddr.sa_data;
1466
1467 // formatted mac address
1468 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]);
1469
1470 return mac_address;
1471}
Girish Gowdra252f4972020-09-07 21:24:01 -07001472
1473void update_voltha_flow_to_cache(uint64_t voltha_flow_id, device_flow dev_flow) {
1474 OPENOLT_LOG(DEBUG, openolt_log_id, "updating voltha flow=%lu to cache\n", voltha_flow_id)
1475 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1476 voltha_flow_to_device_flow[voltha_flow_id] = dev_flow;
1477 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1478}
1479
1480void remove_voltha_flow_from_cache(uint64_t voltha_flow_id) {
1481 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1482 std::map<uint64_t, device_flow>::const_iterator it = voltha_flow_to_device_flow.find(voltha_flow_id);
1483 if (it != voltha_flow_to_device_flow.end()) {
1484 voltha_flow_to_device_flow.erase(it);
1485 }
1486 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1487}
1488
1489bool is_voltha_flow_installed(uint64_t voltha_flow_id ) {
1490 int count;
1491 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1492 count = voltha_flow_to_device_flow.count(voltha_flow_id);
1493 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1494
1495 return count > 0 ? true : false;
1496}
1497
1498const device_flow_params* get_device_flow_params(uint64_t voltha_flow_id) {
1499 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1500 std::map<uint64_t, device_flow>::const_iterator it = voltha_flow_to_device_flow.find(voltha_flow_id);
1501 if (it != voltha_flow_to_device_flow.end()) {
1502 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1503 return it->second.params;
1504 }
1505 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1506
1507 return NULL;
1508}
1509
1510const device_flow* get_device_flow(uint64_t voltha_flow_id) {
1511 bcmos_fastlock_lock(&voltha_flow_to_device_flow_lock);
1512 std::map<uint64_t, device_flow>::const_iterator it = voltha_flow_to_device_flow.find(voltha_flow_id);
1513 if (it != voltha_flow_to_device_flow.end()) {
1514 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1515 return &it->second;
1516 }
1517 bcmos_fastlock_unlock(&voltha_flow_to_device_flow_lock, 0);
1518
1519 return NULL;
1520}
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001521
1522trap_to_host_packet_type get_trap_to_host_packet_type(const ::openolt::Classifier& classifier) {
1523 trap_to_host_packet_type type = unsupported_trap_to_host_pkt_type;
1524 if (classifier.eth_type() == EAP_ETH_TYPE) {
1525 type = eap;
1526 } else if (classifier.src_port() == DHCP_SERVER_SRC_PORT || classifier.src_port() == DHCP_CLIENT_SRC_PORT) {
1527 type = dhcpv4;
1528 } else if (classifier.eth_type() == LLDP_ETH_TYPE) {
1529 type = lldp;
1530 } else if (classifier.ip_proto() == IGMPv4_PROTOCOL) {
1531 type = igmpv4;
Marcos Aurelio Carrero (Furukawa)c4c56b32021-03-08 12:20:34 -03001532 } else if (classifier.eth_type() == PPPoED_ETH_TYPE) {
Marcos Aurelio Carrero (Furukawa)cfe3e0d2021-03-03 10:36:56 -03001533 type = pppoed;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001534 }
1535
1536 return type;
1537}
1538
1539// is_packet_allowed extracts the VLAN, packet-type, interface-type, interface-id from incoming trap-to-host packet.
1540// Then it verifies if this packet can be allowed upstream to host. It does this by checking if the vlan in the incoming packet
1541//exists in trap_to_host_vlan_ids_for_trap_to_host_pkt_info map for (interface-type, interface-id, packet-type) key.
1542bool is_packet_allowed(bcmolt_access_control_receive_eth_packet_data *data, int32_t gemport_id) {
1543 bcmolt_interface_type intf_type = data->interface_ref.intf_type;
1544 uint32_t intf_id = data->interface_ref.intf_id;
1545 trap_to_host_packet_type pkt_type = unsupported_trap_to_host_pkt_type;
1546 uint16_t vlan_id = 0;
1547 int ethType;
1548
1549 struct timeval dummy_tv = {0, 0};
1550 bool free_memory_of_raw_packet = false; // This indicates the pcap library to not free the message buffer. It will freed by the caller.
1551
1552 pcpp::RawPacket rawPacket(data->buffer.arr, data->buffer.len, dummy_tv, free_memory_of_raw_packet, pcpp::LINKTYPE_ETHERNET);
1553 pcpp::Packet parsedPacket(&rawPacket);
1554 pcpp::EthLayer* ethernetLayer = parsedPacket.getLayerOfType<pcpp::EthLayer>();
1555 if (ethernetLayer == NULL)
1556 {
1557 OPENOLT_LOG(ERROR, openolt_log_id, "Something went wrong, couldn't find Ethernet layer\n");
1558 return false;
1559 }
1560
1561 // Getting Vlan layer
1562 pcpp::VlanLayer* vlanLayer = parsedPacket.getLayerOfType<pcpp::VlanLayer>();
1563 if (vlanLayer == NULL)
1564 {
1565 // Allow Untagged LLDP Ether type packet to trap from NNI
1566 if (ntohs(ethernetLayer->getEthHeader()->etherType) == LLDP_ETH_TYPE && intf_type == BCMOLT_INTERFACE_TYPE_NNI) {
1567 return true;
1568 } else {
1569 OPENOLT_LOG(WARNING, openolt_log_id, "untagged packets other than lldp packets are dropped. ethertype=%d, intftype=%d, intf_id=%d\n",
1570 ntohs(ethernetLayer->getEthHeader()->etherType), intf_type, intf_id);
1571 return false;
1572 }
1573 } else {
1574 ethType = ntohs(vlanLayer->getVlanHeader()->etherType);
1575 if (ethType == EAP_ETH_TYPE) { // single tagged packet with EAPoL payload
1576 vlan_id = vlanLayer->getVlanID();
1577 pkt_type = eap;
Marcos Aurelio Carrero (Furukawa)cfe3e0d2021-03-03 10:36:56 -03001578 } else if (ethType == PPPoED_ETH_TYPE) { // single tagged packet with PPPOeD payload
1579 vlan_id = vlanLayer->getVlanID();
1580 pkt_type = pppoed;
Girish Gowdra1935e6a2020-10-31 21:48:22 -07001581 } else if (ethType == IPV4_ETH_TYPE) { // single tagged packet with IPv4 payload
1582 vlan_id = vlanLayer->getVlanID();
1583 vlanLayer->parseNextLayer();
1584 pcpp::IPv4Layer *ipv4Layer = (pcpp::IPv4Layer*)vlanLayer->getNextLayer();
1585 if(ipv4Layer->getIPv4Header()->protocol == UDP_PROTOCOL) { // UDP payload
1586 // Check the UDP Ports to see if it is a DHCPv4 packet
1587 ipv4Layer->parseNextLayer();
1588 pcpp::UdpLayer *udpLayer = (pcpp::UdpLayer*)ipv4Layer->getNextLayer();
1589 if (ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_SERVER_SRC_PORT|| ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_CLIENT_SRC_PORT) {
1590 pkt_type = dhcpv4;
1591 } else {
1592 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported udp source port = %d\n", ntohs(udpLayer->getUdpHeader()->portSrc));
1593 return false;
1594 }
1595 } else if (ipv4Layer->getIPv4Header()->protocol == IGMPv4_PROTOCOL) { // Igmpv4 payload
1596 pkt_type = igmpv4;
1597 } else {
1598 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported ip protocol = %d\n", ipv4Layer->getIPv4Header()->protocol);
1599 return false;
1600 }
1601 } else if (ethType == VLAN_ETH_TYPE) { // double tagged packet
1602
1603 // Trap-to-host from NNI flows do not specify the VLANs, so no vlan validation is necessary.
1604 if (intf_type == BCMOLT_INTERFACE_TYPE_NNI) {
1605 return true;
1606 }
1607
1608 // Here we parse the inner vlan payload and currently support only IPv4 packets
1609
1610 // Extract the vlan_id for trap-to-host packets arriving from the PON
1611 // trap-to-host ACLs from the NNI do not care about VLAN.
1612 if (intf_type == BCMOLT_INTERFACE_TYPE_PON) {
1613 vlan_id = vlanLayer->getVlanID(); // This is the outer vlan id
1614 }
1615 vlanLayer->parseNextLayer();
1616 vlanLayer = (pcpp::VlanLayer*)vlanLayer->getNextLayer(); // Here we extract the inner vlan layer
1617 ethType = ntohs(vlanLayer->getVlanHeader()->etherType);
1618 if (ethType == IPV4_ETH_TYPE) { // IPv4
1619 uint16_t _inner_vlan_id = vlanLayer->getVlanID();
1620 vlanLayer->parseNextLayer();
1621 pcpp::IPv4Layer *ipv4Layer = (pcpp::IPv4Layer*)vlanLayer->getNextLayer(); // here we extract the inner vlan IPv4 payload
1622 if(ipv4Layer->getIPv4Header()->protocol == UDP_PROTOCOL) { // UDP payload
1623 // Check the UDP Ports to see if it is a DHCPv4 packet
1624 ipv4Layer->parseNextLayer();
1625 pcpp::UdpLayer *udpLayer = (pcpp::UdpLayer*)ipv4Layer->getNextLayer();
1626 if (ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_SERVER_SRC_PORT || ntohs(udpLayer->getUdpHeader()->portSrc) == DHCP_CLIENT_SRC_PORT) {
1627 pkt_type = dhcpv4;
1628 } else {
1629 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported udp source port = %d\n", ntohs(udpLayer->getUdpHeader()->portSrc));
1630 return false;
1631 }
1632 } else if (ipv4Layer->getIPv4Header()->protocol == IGMPv4_PROTOCOL) { // Igmpv4 payload
1633 pkt_type = igmpv4;
1634 } else {
1635 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported ip protocol = %d\n", ipv4Layer->getIPv4Header()->protocol)
1636 return false;
1637 }
1638 }
1639 } else {
1640 OPENOLT_LOG(ERROR, openolt_log_id, "unsupported ether type = 0x%x\n", ntohs((vlanLayer->getVlanHeader()->etherType)));
1641 return false;
1642 }
1643 }
1644
1645#if 0 // Debug logs for test purpose only
1646 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";
1647 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();
1648 it != trap_to_host_vlan_ids_for_trap_to_host_pkt_info.end(); ++it)
1649 {
1650 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";
1651 std::cout << "vlans for the above key are => ";
1652 for (std::list<uint16_t>::const_iterator _it=it->second.begin();
1653 _it != it->second.end();
1654 ++_it) {
1655 std::cout << *_it << " ";
1656 }
1657 std::cout << "\n\n";
1658 }
1659#endif
1660
1661 trap_to_host_pkt_info pkt_info(intf_type, intf_id, pkt_type, gemport_id);
1662 // 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
1663 if (trap_to_host_vlan_ids_for_trap_to_host_pkt_info.count(pkt_info) > 0) {
1664 // Iterate throught the vlan list to find matching vlan
1665 auto& vlan_id_list = trap_to_host_vlan_ids_for_trap_to_host_pkt_info[pkt_info];
1666 for (auto allowed_vlan_id : vlan_id_list) {
1667 // Found exact matching vlan in the allowed list of vlans for the trap_to_host_pkt_info key or
1668 // there is generic match ANY_VLAN in the list in the allowed vlan list.
1669 if (allowed_vlan_id == vlan_id || allowed_vlan_id == ANY_VLAN) {
1670 return true;
1671 }
1672 }
1673 }
1674 return false;
1675}