blob: c6f4cbf9b3f396a5359d7c48681182d477e473d8 [file] [log] [blame]
Girish Gowdrab0337eb2022-03-25 16:44:21 -07001/*
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 "device.h"
18#include "vendor.h"
19#include "core_utils.h"
20
21using namespace std;
22
23// PonTrxBase class member function definitions
24// Note: 'cout' logger has been used in this file instead of OPENOLT_LOG
25// because the logger task may not be initialized in the openolt core module
26// before PonTrx module is initialized in the main handler. In that case,
27// any OPENOLT_LOG logger (which internally uses BCM_LOG) will not be logged.
28
29PonTrxBase::PonTrxBase(string eeprom_file_name,
30 int port_addr,
31 string eeprom_file_path_name,
32 string sfp_presence_command) :
33 _eeprom_file_name{eeprom_file_name},
34 _port_addr{port_addr},
35 _eeprom_file_path_format{eeprom_file_path_name},
36 _sfp_presence_command{sfp_presence_command}
37{
38}
39
40PonTrxBase::~PonTrxBase() {
41 for (auto it : _t_data) {
42 delete it;
43 }
44}
45
46// returns the _sfp_presence_data
47const set<int> PonTrxBase::get_sfp_presence_data() {
48 return _sfp_presence_data;
49}
50
51// reads, updates and returns the _sfp_presence_data
52const set<int> PonTrxBase::read_sfp_presence_data() {
53 set<int> sp;
54 // command to read the sfp presence array
55 // The sample output of the command looks like below
56 // root@localhost:~# onlpdump -p
57 // Presence: 0 1 16
58 const string& command = _sfp_presence_command;
59 int status_code = system((command + " > temp.txt").c_str());
60 if (status_code != 0) {
61 perror("error getting sfp presence array from ONL\n");
62 // return the current _sfp_presence_data
63 return _sfp_presence_data;
64 }
65 ifstream ifs("temp.txt");
66 string res = {istreambuf_iterator<char>(ifs), istreambuf_iterator<char>()};
67 ifs.close(); // must close the inout stream so the file can be cleaned up
68 // If there is issue reading the sfp presence array, print error and return existing data
69 if (remove("temp.txt") != 0) {
70 perror("Error deleting temporary file");
71 // return the current sfp presence array
72 return _sfp_presence_data;
73 }
74
75 // parse the output of sfp presence command and read which PON Trx are connected/disconnected now
76 stringstream ss(res);
77 string s;
78 while (getline(ss, s, ' ')) {
79 try {
80 int i = stoi(s);
81 // Set the Trx port index corresponding the PON port to true if it appears on the sfp presence command output
82 if (i < TOTAL_PON_TRX_PORTS) {
83 sp.insert(i);
84 }
85
86 } catch(invalid_argument) {
87 // do nothing
88 } catch(out_of_range) {
89 // do nothing
90 }
91 }
92
93 // If the current _sfp_presence_data is not same the newly read data,
94 // update local copy and also raise an event.
95 if (sp != _sfp_presence_data) {
96 cout << "sfp presence data has been updated\n";
97
98 set<int> sfp_ports_up, sfp_ports_down;
99
100 set_difference(sp.begin(), sp.end(), _sfp_presence_data.begin(), _sfp_presence_data.end(), inserter(sfp_ports_up, sfp_ports_up.begin()));
101 // New SFPs are detected
102 if (sfp_ports_up.size() > 0) {
103 cout << "following pon sfp ports are up: ";
104 for (auto up_it : sfp_ports_up) {
105 cout << up_it << " ";
106 }
107 cout << "\n";
108 }
109 set_difference(_sfp_presence_data.begin(), _sfp_presence_data.end(), sp.begin(), sp.end(), inserter(sfp_ports_down, sfp_ports_down.begin()));
110 // Some SFPs are down
111 if (sfp_ports_down.size() > 0) {
112 cout << "following pon sfp ports are down: \n";
113 for (auto down_it : sfp_ports_down) {
114 cout << down_it << " ";
115 }
116 cout << "\n";
117 }
118
119 // FIXME: raise an event for all the PON Trx ports that have been updated
120 _sfp_presence_data = sp;
121 }
122
123 return _sfp_presence_data;
124}
125
126// reads the EEPROM data. The sfp_index is the bus index corresponding to the PON Trx
127// returns true if success
128bool PonTrxBase::read_eeprom_data_for_sfp(int sfp_index) {
129 ifstream is;
130 int len;
131 array<char, EEPROM_READ_PATH_SIZE> path{};
132 array<unsigned char, EEPROM_DATA_READ_SIZE> data{};
133
134 if (sfp_index >= TOTAL_PON_TRX_PORTS) {
135 perror("invalid pon trx index\n");
136 return false;
137 }
138
139 if (_eeprom_read_path.count(sfp_index) == 0) {
140 _eeprom_read_path[sfp_index] = path;
141 char file_name[PON_TRX_BUS_FORMAT_SIZE];
142 char *tmp_place_holder = new char[PON_TRX_BUS_FORMAT_SIZE];
143 // 4 is max length of _port_addr
144 if ((_eeprom_file_path_format.length() + _eeprom_file_name.length() + 4) > PON_TRX_BUS_FORMAT_SIZE) {
145 cerr << "resultant eeprom file length too long\n";
146 delete []tmp_place_holder;
147 return false;
148 }
149 strcpy(tmp_place_holder, _eeprom_file_path_format.c_str());
150 sprintf(file_name, tmp_place_holder, bus_index[sfp_index], _port_addr, _eeprom_file_name.c_str());
151 memcpy(&_eeprom_read_path[sfp_index][0], file_name, PON_TRX_BUS_FORMAT_SIZE);
152 delete []tmp_place_holder;
153 }
154 cout << "eeprom file to read is: " << _eeprom_read_path[sfp_index].data() << "for sfp " << sfp_index << endl;
155 FILE* fp = fopen(_eeprom_read_path[sfp_index].data(), "rb");
156 if (!fp) {
157 perror("failed to open file");
158 _eeprom_read_path.erase(sfp_index);
159 return false;
160 }
161 _eeprom_data[sfp_index] = data;
162 int val, cnt = 0;
163
164 // Populate EEPROM data
165 while ((val = fgetc(fp)) != EOF && cnt < EEPROM_DATA_READ_SIZE) {
166 _eeprom_data[sfp_index][cnt] = (unsigned char)val;
167 cnt++;
168 }
169 fclose(fp);
170 if (cnt != EEPROM_DATA_READ_SIZE) {
171 cerr << "invalid length of data read:" << cnt << endl;
172 _eeprom_read_path.erase(sfp_index);
173 _eeprom_data.erase(sfp_index);
174 return false;
175 }
176
177 return true;
178}
179
180// decodes the EEPROM data. The sfp_index is the bus index corresponding to the PON Trx
181// returns true if success
182bool PonTrxBase::decode_eeprom_data(int sfp_index) {
183 /*
184 try {
185 */
186
187 trx_data tmp, *store=NULL;
188 tmp.sfp_index = sfp_index;
189
190 // decode vendor name
191 array<unsigned char, EEPROM_VENDOR_NAME_LENGTH> vn{};
192 copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_NAME_START_IDX],
193 &_eeprom_data[sfp_index][EEPROM_VENDOR_NAME_START_IDX] + EEPROM_VENDOR_NAME_LENGTH,
194 &vn[0]);
195 pair<string, bool> res_str = hex_to_ascii_string(vn.data(), vn.max_size());
196 if (!res_str.second) {
197 perror("error decoding vendor name\n");
198 return false;
199 }
200 tmp.vendor_name = res_str.first;
201 cout << "[" << sfp_index << "]" << " vendor name: " << tmp.vendor_name << endl;
202
203
204 // decode vendor oui
205 array<unsigned char, EEPROM_VENDOR_OUI_LENGTH> oui{};
206 copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_OUI_START_IDX],
207 &_eeprom_data[sfp_index][EEPROM_VENDOR_OUI_START_IDX] + EEPROM_VENDOR_OUI_LENGTH,
208 &oui[0]);
209 res_str = hex_to_ascii_string(oui.data(), oui.max_size());
210 if (!res_str.second) {
211 perror("error decoding vendor oui\n");
212 return false;
213 }
214 if (res_str.first.length() == 3) { // vendor_oui length is 3
215 memcpy(tmp.vendor_oui, res_str.first.c_str(), 3);
216 }
217 cout << "[" << sfp_index << "]" << " vendor oui: " << res_str.first << endl;
218
219 // decode vendor part number
220 array<unsigned char, EEPROM_VENDOR_PART_NUMBER_LENGTH> pn{};
221 copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_PART_NUMBER_START_IDX],
222 &_eeprom_data[sfp_index][EEPROM_VENDOR_PART_NUMBER_START_IDX] + EEPROM_VENDOR_PART_NUMBER_LENGTH,
223 &pn[0]);
224 res_str = hex_to_ascii_string(pn.data(), pn.max_size());
225 if (!res_str.second) {
226 perror("error decoding vendor part number\n");
227 return false;
228 }
229 tmp.vendor_part_no = res_str.first;
230 cout << "[" << sfp_index << "]" << " vendor pn: " << tmp.vendor_part_no << endl;
231
232 // decode vendor revision
233 array<unsigned char, EEPROM_VENDOR_REVISION_LENGTH> rev{};
234 copy(&_eeprom_data[sfp_index][EEPROM_VENDOR_REVISION_START_IDX],
235 &_eeprom_data[sfp_index][EEPROM_VENDOR_REVISION_START_IDX] + EEPROM_VENDOR_REVISION_LENGTH,
236 &rev[0]);
237 res_str = hex_to_ascii_string(rev.data(), rev.max_size());
238 if (!res_str.second) {
239 perror("error decoding vendor revision\n");
240 return false;
241 }
242 tmp.vendor_rev = res_str.first;
243 cout << "[" << sfp_index << "]" << " vendor rev: " << tmp.vendor_rev << endl;
244
245 // decode pon wavelength(s)
246 array<unsigned char, EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH> wv{};
247 copy(&_eeprom_data[sfp_index][EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX],
248 &_eeprom_data[sfp_index][EEPROM_DOWNSTREAM_WAVELENGTH_START_IDX] + EEPROM_DOWNSTREAM_WAVELENGTH_LENGTH,
249 &wv[0]);
250 pair<uint32_t, bool> res_uint = hex_to_uinteger(wv.data(), wv.max_size());
251 if (!res_uint.second) {
252 perror("error decoding primary downstream wavelength\n");
253 return false;
254 }
255 tmp.p_data[0].valid = true;
256 tmp.p_data[0].wavelength = res_uint.first * EEPROM_WAVELENGTH_RESOLUTION;
257 tmp.p_data[0].pon_type = get_pon_type_from_wavelength(tmp.p_data[0].wavelength);
258 cout << "[" << sfp_index << "]" << " pon wavelength: " << tmp.p_data[0].wavelength << endl;
259 // TODO: also fill the field pon_type
260
261 // TODO: Let's ignore secondary wavelength decode for now as we do not know how the secondary wavelength is represent on the Combo PON
262 tmp.p_data[1].valid = false;
263
264 store = new(nothrow) trx_data;
265 if (store == NULL) {
266 perror("could not allocate memory for trx_data");
267 return false;
268 }
269
270 // Copy data
271 store->sfp_index = sfp_index;
272 store->vendor_name = tmp.vendor_name;
273 memcpy(store->vendor_oui, tmp.vendor_oui, 3);
274 store->vendor_part_no = tmp.vendor_part_no;
275 store->vendor_rev = tmp.vendor_rev;
276 store->trx_type = tmp.trx_type;
277 for (int i = 0; i < MAX_PONS_PER_TRX; i++) {
278 store->p_data[i].valid = tmp.p_data[i].valid;
279 store->p_data[i].wavelength = tmp.p_data[i].wavelength;
280 store->p_data[i].pon_type = tmp.p_data[i].pon_type;
281 }
282
283 _t_data.insert(store);
284 /*
285 } catch(...) { // FIXME: Put specific exceptions here
286 perror("caught exception\n");
287 return false;
288 }
289 */
290 return true;
291}
292
293bcmolt_pon_type PonTrxBase::get_pon_type_from_wavelength(int wavelength) {
294 bcmolt_pon_type pon_type = BCMOLT_PON_TYPE_UNKNOWN;
295 switch (wavelength) {
296 case GPON_DOWNSTREAM_WAVELENGTH_NM:
297 pon_type = BCMOLT_PON_TYPE_GPON;
298 case XGSPON_DOWNSTREAM_WAVELENGTH_NM:
299 pon_type = BCMOLT_PON_TYPE_XGPON;
300 // Add more in the future as needed.
301 }
302 return pon_type;
303}
304
305bcmolt_pon_type PonTrxBase::get_sfp_mode(int sfp_index) {
306 bcmolt_pon_type pon0_type = BCMOLT_PON_TYPE_UNKNOWN;
307 bcmolt_pon_type pon1_type = BCMOLT_PON_TYPE_UNKNOWN;
308 trx_data *td = NULL;
309 set<trx_data*>::iterator it;
310 // Iterate the trx data set and break if we find a trx data with mathcing sfp index
311 for (it = _t_data.begin(); it != _t_data.end(); it++) {
312 if ((*it)->sfp_index == sfp_index) {
313 td = *it;
314 break;
315 }
316 }
317 if (it == _t_data.end()) {
318 perror("end of iterator, pon type not detected");
319 return pon0_type;
320 }
321 if (td == NULL) {
322 cerr << "trx data is null\n";
323 return pon0_type;
324 }
325
326 // Find the PON type/mode
327 if (td->p_data[0].valid) {
328 pon0_type = td->p_data[0].pon_type;
329 if (pon0_type == BCMOLT_PON_TYPE_UNKNOWN) {
330 return pon0_type;
331 }
332 if (td->p_data[1].valid) {
333 pon1_type = td->p_data[1].pon_type;
334 if (pon1_type == BCMOLT_PON_TYPE_UNKNOWN) {
335 return pon1_type;
336 }
337
338 if (pon0_type == pon1_type) {
339 return pon0_type;
340 } else {
341 return BCMOLT_PON_TYPE_XGPON_GPON_WDMA; // Combo SFP!
342 }
343 }
344 return pon0_type;
345 }
346
347 return pon0_type;
348}
349
350// Returns the MAC System Mode based on the set of SFP IDs provided.
351// The derived class will most likely need to override this method to provide a
352// different implementation for that particular OLT platform.
353pair<bcmolt_system_mode, bool> PonTrxBase::get_mac_system_mode(int olt_mac_id, set<int> sfp_ids) {
354 bool ret = true;
355 bcmolt_system_mode sm = BCMOLT_SYSTEM_MODE_GPON__16_X;
356
357 return {sm, ret};
358}
359
360// Get trx data for sfp
361trx_data* PonTrxBase::get_trx_data(int sfp_index) {
362 for (auto it : _t_data) {
363 if (it->sfp_index == sfp_index) {
364 cout << "[" << sfp_index << "]" << " found trx data\n";
365 return (it);
366 }
367 }
368 return NULL;
369}