blob: e13abedc953ed8a57c4071e1d3f76abfabb309d5 [file] [log] [blame]
Abhilash S.L765ad002019-04-24 16:40:57 +05301/*
2 * Copyright 2019-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 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070016
Scott Bakerdbd960e2020-02-28 08:57:51 -080017//Package core provides the utility for olt devices, flows and statistics
18package core
Abhilash S.L765ad002019-04-24 16:40:57 +053019
20import (
kesavand62126212021-01-12 04:56:06 -050021 "container/list"
Neha Sharma96b7bf22020-06-15 10:37:32 +000022 "context"
Abhilash S.L765ad002019-04-24 16:40:57 +053023 "fmt"
Gamze Abakafcbd6e72020-12-17 13:25:16 +000024 rsrcMgr "github.com/opencord/voltha-openolt-adapter/internal/pkg/resourcemanager"
Shrey Baid26912972020-04-16 21:02:31 +053025 "sync"
26 "time"
27
Girish Gowdraa09aeab2020-09-14 16:30:52 -070028 "github.com/opencord/voltha-lib-go/v4/pkg/log"
Thomas Lee S94109f12020-03-03 16:39:29 +053029 "github.com/opencord/voltha-openolt-adapter/internal/pkg/olterrors"
kesavand62126212021-01-12 04:56:06 -050030 "github.com/opencord/voltha-protos/v4/go/extension"
Girish Gowdraa09aeab2020-09-14 16:30:52 -070031 "github.com/opencord/voltha-protos/v4/go/openolt"
32 "github.com/opencord/voltha-protos/v4/go/voltha"
Abhilash S.L765ad002019-04-24 16:40:57 +053033)
34
Gamze Abakafcbd6e72020-12-17 13:25:16 +000035const (
36 //NNIStats statType constant
37 NNIStats = "NNIStats"
38 //PONStats statType constant
39 PONStats = "PONStats"
40 //ONUStats statType constant
41 ONUStats = "ONUStats"
42 //GEMStats statType constant
43 GEMStats = "GEMStats"
44
45 //RxBytes constant
46 RxBytes = "RxBytes"
47 //RxPackets constant
48 RxPackets = "RxPackets"
49 //TxBytes constant
50 TxBytes = "TxBytes"
51 //TxPackets constant
52 TxPackets = "TxPackets"
53 //FecCodewords constant
54 FecCodewords = "FecCodewords"
55 //BipUnits constant
56 BipUnits = "BipUnits"
57 //BipErrors constant
58 BipErrors = "BipErrors"
59 //RxPloamsNonIdle constant
60 RxPloamsNonIdle = "RxPloamsNonIdle"
61 //RxPloamsError constant
62 RxPloamsError = "RxPloamsError"
63 //RxOmci constant
64 RxOmci = "RxOmci"
65 //RxOmciPacketsCrcError constant
66 RxOmciPacketsCrcError = "RxOmciPacketsCrcError"
67 //PositiveDrift constant
68 PositiveDrift = "PositiveDrift"
69 //NegativeDrift constant
70 NegativeDrift = "NegativeDrift"
71 //DelimiterMissDetection constant
72 DelimiterMissDetection = "DelimiterMissDetection"
73 //FecCorrectedSymbols constant
74 FecCorrectedSymbols = "FecCorrectedSymbols"
75 //FecCodewordsCorrected constant
76 FecCodewordsCorrected = "FecCodewordsCorrected"
77 //fecCodewordsUncorrectable constant
78 fecCodewordsUncorrectable = "fec_codewords_uncorrectable"
79 //FecCorrectedUnits constant
80 FecCorrectedUnits = "FecCorrectedUnits"
81 //XGEMKeyErrors constant
82 XGEMKeyErrors = "XGEMKeyErrors"
83 //XGEMLoss constant
84 XGEMLoss = "XGEMLOSS"
85 //BerReported constant
86 BerReported = "BerReported"
87 //LcdgErrors constant
88 LcdgErrors = "LcdgErrors"
89 //RdiErrors constant
90 RdiErrors = "RdiErrors"
91)
92
Naga Manjunath7615e552019-10-11 22:35:47 +053093var mutex = &sync.Mutex{}
94
Gamze Abakafcbd6e72020-12-17 13:25:16 +000095var onuStats = make(chan *openolt.OnuStatistics, 100)
96var gemStats = make(chan *openolt.GemPortStatistics, 100)
97
kesavand62126212021-01-12 04:56:06 -050098//statRegInfo is used to register for notifications
99//on receiving port stats and flow stats indication
100type statRegInfo struct {
101 chn chan bool
102 portNo uint32
103 portType extension.GetOltPortCounters_PortType
104}
105
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700106// PonPort representation
Abhilash S.L765ad002019-04-24 16:40:57 +0530107type PonPort struct {
108 /*
109 This is a highly reduced version taken from the adtran pon_port.
110 TODO: Extend for use in the openolt adapter set.
111 */
112 /* MAX_ONUS_SUPPORTED = 256
113 DEFAULT_ENABLED = False
114 MAX_DEPLOYMENT_RANGE = 25000 # Meters (OLT-PB maximum)
115
116 _MCAST_ONU_ID = 253
117 _MCAST_ALLOC_BASE = 0x500
118
119 _SUPPORTED_ACTIVATION_METHODS = ['autodiscovery'] # , 'autoactivate']
120 _SUPPORTED_AUTHENTICATION_METHODS = ['serial-number']
121 */
122 PONID uint32
123 DeviceID string
124 IntfID uint32
125 PortNum uint32
126 PortID uint32
127 Label string
128 ONUs map[uint32]interface{}
129 ONUsByID map[uint32]interface{}
130
131 RxBytes uint64
132 RxPackets uint64
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000133 RxUcastPackets uint64
Abhilash S.L765ad002019-04-24 16:40:57 +0530134 RxMcastPackets uint64
135 RxBcastPackets uint64
136 RxErrorPackets uint64
137 TxBytes uint64
138 TxPackets uint64
139 TxUcastPackets uint64
140 TxMcastPackets uint64
141 TxBcastPackets uint64
142 TxErrorPackets uint64
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000143 RxCrcErrors uint64
144 BipErrors uint64
Abhilash S.L765ad002019-04-24 16:40:57 +0530145}
146
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700147// NewPONPort returns a new instance of PonPort initialized with given PONID, DeviceID, IntfID and PortNum
Abhilash S.L765ad002019-04-24 16:40:57 +0530148func NewPONPort(PONID uint32, DeviceID string, IntfID uint32, PortNum uint32) *PonPort {
149
150 var PON PonPort
151
152 PON.PONID = PONID
153 PON.DeviceID = DeviceID
154 PON.IntfID = IntfID
155 PON.PortNum = PortNum
156 PON.PortID = 0
Naga Manjunath7615e552019-10-11 22:35:47 +0530157 PON.Label = fmt.Sprintf("%s%d", "pon-", PONID)
Abhilash S.L765ad002019-04-24 16:40:57 +0530158
159 PON.ONUs = make(map[uint32]interface{})
160 PON.ONUsByID = make(map[uint32]interface{})
161
162 /*
163 Statistics taken from nni_port
164 self.intf_id = 0 #handled by getter
165 self.port_no = 0 #handled by getter
166 self.port_id = 0 #handled by getter
167
168 Note: In the current implementation of the kpis coming from the BAL the stats are the
169 samne model for NNI and PON.
170
171 TODO: Integrate additional kpis for the PON and other southbound port objecgts.
172
173 */
174
175 PON.RxBytes = 0
176 PON.RxPackets = 0
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000177 PON.RxUcastPackets = 0
Abhilash S.L765ad002019-04-24 16:40:57 +0530178 PON.RxMcastPackets = 0
179 PON.RxBcastPackets = 0
180 PON.RxErrorPackets = 0
181 PON.TxBytes = 0
182 PON.TxPackets = 0
183 PON.TxUcastPackets = 0
184 PON.TxMcastPackets = 0
185 PON.TxBcastPackets = 0
186 PON.TxErrorPackets = 0
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000187 PON.RxCrcErrors = 0
188 PON.BipErrors = 0
Abhilash S.L765ad002019-04-24 16:40:57 +0530189
190 /* def __str__(self):
191 return "PonPort-{}: Admin: {}, Oper: {}, OLT: {}".format(self._label,
192 self._admin_state,
193 self._oper_status,
194 self.olt)
195 */
196 return &PON
197}
198
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700199// NniPort representation
Abhilash S.L765ad002019-04-24 16:40:57 +0530200type NniPort struct {
201 /*
202 Northbound network port, often Ethernet-based
203
204 This is a highly reduced version taken from the adtran nni_port code set
205 TODO: add functions to allow for port specific values and operations
206 */
207 PortNum uint32
208 Name string
209 LogicalPort uint32
210 IntfID uint32
211
212 RxBytes uint64
213 RxPackets uint64
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000214 RxUcastPackets uint64
Abhilash S.L765ad002019-04-24 16:40:57 +0530215 RxMcastPackets uint64
216 RxBcastPackets uint64
217 RxErrorPackets uint64
218 TxBytes uint64
219 TxPackets uint64
220 TxUcastPackets uint64
221 TxMcastPackets uint64
222 TxBcastPackets uint64
223 TxErrorPackets uint64
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000224 RxCrcErrors uint64
225 BipErrors uint64
Abhilash S.L765ad002019-04-24 16:40:57 +0530226}
227
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700228// NewNniPort returns a new instance of NniPort initialized with the given PortNum and IntfID
Abhilash S.L765ad002019-04-24 16:40:57 +0530229func NewNniPort(PortNum uint32, IntfID uint32) *NniPort {
230
231 var NNI NniPort
232
233 NNI.PortNum = PortNum
Naga Manjunath7615e552019-10-11 22:35:47 +0530234 NNI.Name = fmt.Sprintf("%s%d", "nni-", PortNum)
Abhilash S.L765ad002019-04-24 16:40:57 +0530235 NNI.IntfID = IntfID
236
237 NNI.RxBytes = 0
238 NNI.RxPackets = 0
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000239 NNI.RxUcastPackets = 0
Abhilash S.L765ad002019-04-24 16:40:57 +0530240 NNI.RxMcastPackets = 0
241 NNI.RxBcastPackets = 0
242 NNI.RxErrorPackets = 0
243 NNI.TxBytes = 0
244 NNI.TxPackets = 0
245 NNI.TxUcastPackets = 0
246 NNI.TxMcastPackets = 0
247 NNI.TxBcastPackets = 0
248 NNI.TxErrorPackets = 0
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000249 NNI.RxCrcErrors = 0
250 NNI.BipErrors = 0
Abhilash S.L765ad002019-04-24 16:40:57 +0530251
252 return &NNI
253}
254
kesavand62126212021-01-12 04:56:06 -0500255//StatType defines portStatsType and flowStatsType types
256type StatType int
257
258const (
259 portStatsType StatType = iota
260 flowStatsType
261)
262
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700263// OpenOltStatisticsMgr structure
Abhilash S.L765ad002019-04-24 16:40:57 +0530264type OpenOltStatisticsMgr struct {
265 Device *DeviceHandler
Naga Manjunath7615e552019-10-11 22:35:47 +0530266 NorthBoundPort map[uint32]*NniPort
267 SouthBoundPort map[uint32]*PonPort
Abhilash S.L765ad002019-04-24 16:40:57 +0530268 // TODO PMMetrics Metrics
kesavand62126212021-01-12 04:56:06 -0500269 //statIndListners is the list of requests to be notified when port and flow stats indication is received
270 statIndListnerMu sync.Mutex
271 statIndListners map[StatType]*list.List
Abhilash S.L765ad002019-04-24 16:40:57 +0530272}
273
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700274// NewOpenOltStatsMgr returns a new instance of the OpenOltStatisticsMgr
Neha Sharma96b7bf22020-06-15 10:37:32 +0000275func NewOpenOltStatsMgr(ctx context.Context, Dev *DeviceHandler) *OpenOltStatisticsMgr {
Abhilash S.L765ad002019-04-24 16:40:57 +0530276
277 var StatMgr OpenOltStatisticsMgr
278
279 StatMgr.Device = Dev
280 // TODO call metric PMMetric =
281 // Northbound and Southbound ports
282 // added to initialize the pm_metrics
283 var Ports interface{}
Neha Sharma96b7bf22020-06-15 10:37:32 +0000284 Ports, _ = InitPorts(ctx, "nni", Dev.device.Id, 1)
Naga Manjunath7615e552019-10-11 22:35:47 +0530285 StatMgr.NorthBoundPort, _ = Ports.(map[uint32]*NniPort)
286 NumPonPorts := Dev.resourceMgr.DevInfo.GetPonPorts()
Neha Sharma96b7bf22020-06-15 10:37:32 +0000287 Ports, _ = InitPorts(ctx, "pon", Dev.device.Id, NumPonPorts)
Naga Manjunath7615e552019-10-11 22:35:47 +0530288 StatMgr.SouthBoundPort, _ = Ports.(map[uint32]*PonPort)
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000289 if StatMgr.Device.openOLT.enableONUStats {
290 go StatMgr.publishOnuStats()
291 }
292 if StatMgr.Device.openOLT.enableGemStats {
293 go StatMgr.publishGemStats()
294 }
kesavand62126212021-01-12 04:56:06 -0500295 StatMgr.statIndListners = make(map[StatType]*list.List)
296 StatMgr.statIndListners[portStatsType] = list.New()
297 StatMgr.statIndListners[flowStatsType] = list.New()
Abhilash S.L765ad002019-04-24 16:40:57 +0530298 return &StatMgr
299}
300
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700301// InitPorts collects the port objects: nni and pon that are updated with the current data from the OLT
Neha Sharma96b7bf22020-06-15 10:37:32 +0000302func InitPorts(ctx context.Context, Intftype string, DeviceID string, numOfPorts uint32) (interface{}, error) {
Abhilash S.L765ad002019-04-24 16:40:57 +0530303 /*
304 This method collects the port objects: nni and pon that are updated with the
305 current data from the OLT
306
307 Both the northbound (nni) and southbound ports are indexed by the interface id (intf_id)
308 and NOT the port number. When the port object is instantiated it will contain the intf_id and
309 port_no values
310
311 :param type:
312 :return:
313 */
314 var i uint32
315 if Intftype == "nni" {
Naga Manjunath7615e552019-10-11 22:35:47 +0530316 NniPorts := make(map[uint32]*NniPort)
317 for i = 0; i < numOfPorts; i++ {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000318 Port := BuildPortObject(ctx, i, "nni", DeviceID).(*NniPort)
Naga Manjunath7615e552019-10-11 22:35:47 +0530319 NniPorts[Port.IntfID] = Port
Abhilash S.L765ad002019-04-24 16:40:57 +0530320 }
321 return NniPorts, nil
322 } else if Intftype == "pon" {
Naga Manjunath7615e552019-10-11 22:35:47 +0530323 PONPorts := make(map[uint32]*PonPort)
324 for i = 0; i < numOfPorts; i++ {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000325 PONPort := BuildPortObject(ctx, i, "pon", DeviceID).(*PonPort)
Naga Manjunath7615e552019-10-11 22:35:47 +0530326 PONPorts[PortNoToIntfID(PONPort.IntfID, voltha.Port_PON_OLT)] = PONPort
Abhilash S.L765ad002019-04-24 16:40:57 +0530327 }
328 return PONPorts, nil
329 } else {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000330 logger.Errorw(ctx, "invalid-type-of-interface", log.Fields{"interface-type": Intftype})
Thomas Lee S94109f12020-03-03 16:39:29 +0530331 return nil, olterrors.NewErrInvalidValue(log.Fields{"interface-type": Intftype}, nil)
Abhilash S.L765ad002019-04-24 16:40:57 +0530332 }
333}
334
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700335// BuildPortObject allows for updating north and southbound ports, newly discovered ports, and devices
Neha Sharma96b7bf22020-06-15 10:37:32 +0000336func BuildPortObject(ctx context.Context, PortNum uint32, IntfType string, DeviceID string) interface{} {
Abhilash S.L765ad002019-04-24 16:40:57 +0530337 /*
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700338 Separate method to allow for updating north and southbound ports
Abhilash S.L765ad002019-04-24 16:40:57 +0530339 newly discovered ports and devices
340
341 :param port_num:
342 :param type:
343 :return:
344 */
345
346 //This builds a port object which is added to the
347 //appropriate northbound or southbound values
348 if IntfType == "nni" {
Naga Manjunath7615e552019-10-11 22:35:47 +0530349 IntfID := IntfIDToPortNo(PortNum, voltha.Port_ETHERNET_NNI)
350 nniID := PortNoToIntfID(IntfID, voltha.Port_ETHERNET_NNI)
Neha Sharma96b7bf22020-06-15 10:37:32 +0000351 logger.Debugw(ctx, "interface-type-nni",
Shrey Baid26912972020-04-16 21:02:31 +0530352 log.Fields{
353 "nni-id": nniID,
354 "intf-type": IntfType})
Naga Manjunath7615e552019-10-11 22:35:47 +0530355 return NewNniPort(PortNum, nniID)
Abhilash S.L765ad002019-04-24 16:40:57 +0530356 } else if IntfType == "pon" {
357 // PON ports require a different configuration
358 // intf_id and pon_id are currently equal.
Naga Manjunath7615e552019-10-11 22:35:47 +0530359 IntfID := IntfIDToPortNo(PortNum, voltha.Port_PON_OLT)
360 PONID := PortNoToIntfID(IntfID, voltha.Port_PON_OLT)
Neha Sharma96b7bf22020-06-15 10:37:32 +0000361 logger.Debugw(ctx, "interface-type-pon",
Shrey Baid26912972020-04-16 21:02:31 +0530362 log.Fields{
363 "pon-id": PONID,
364 "intf-type": IntfType})
Abhilash S.L765ad002019-04-24 16:40:57 +0530365 return NewPONPort(PONID, DeviceID, IntfID, PortNum)
366 } else {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000367 logger.Errorw(ctx, "invalid-type-of-interface", log.Fields{"intf-type": IntfType})
Abhilash S.L765ad002019-04-24 16:40:57 +0530368 return nil
369 }
370}
371
Naga Manjunath7615e552019-10-11 22:35:47 +0530372// collectNNIMetrics will collect the nni port metrics
373func (StatMgr *OpenOltStatisticsMgr) collectNNIMetrics(nniID uint32) map[string]float32 {
374
375 nnival := make(map[string]float32)
376 mutex.Lock()
377 cm := StatMgr.Device.portStats.NorthBoundPort[nniID]
378 mutex.Unlock()
Rohan Agrawalda5e0b22020-05-20 11:10:26 +0000379 metricNames := StatMgr.Device.metrics.GetSubscriberMetrics()
Naga Manjunath7615e552019-10-11 22:35:47 +0530380
Rohan Agrawalda5e0b22020-05-20 11:10:26 +0000381 var metrics []string
Kent Hagermane6ff1012020-07-14 15:07:53 -0400382 for metric := range metricNames {
383 if metricNames[metric].Enabled {
384 metrics = append(metrics, metric)
Naga Manjunath7615e552019-10-11 22:35:47 +0530385 }
386 }
Rohan Agrawalda5e0b22020-05-20 11:10:26 +0000387
388 for _, mName := range metrics {
389 switch mName {
390 case "rx_bytes":
391 nnival["RxBytes"] = float32(cm.RxBytes)
392 case "rx_packets":
393 nnival["RxPackets"] = float32(cm.RxPackets)
394 case "rx_ucast_packets":
395 nnival["RxUcastPackets"] = float32(cm.RxUcastPackets)
396 case "rx_mcast_packets":
397 nnival["RxMcastPackets"] = float32(cm.RxMcastPackets)
398 case "rx_bcast_packets":
399 nnival["RxBcastPackets"] = float32(cm.RxBcastPackets)
400 case "tx_bytes":
401 nnival["TxBytes"] = float32(cm.TxBytes)
402 case "tx_packets":
403 nnival["TxPackets"] = float32(cm.TxPackets)
404 case "tx_mcast_packets":
405 nnival["TxMcastPackets"] = float32(cm.TxMcastPackets)
406 case "tx_bcast_packets":
407 nnival["TxBcastPackets"] = float32(cm.TxBcastPackets)
408 }
409 }
Naga Manjunath7615e552019-10-11 22:35:47 +0530410 return nnival
411}
412
413// collectPONMetrics will collect the pon port metrics
414func (StatMgr *OpenOltStatisticsMgr) collectPONMetrics(pID uint32) map[string]float32 {
415
416 ponval := make(map[string]float32)
417 mutex.Lock()
418 cm := StatMgr.Device.portStats.SouthBoundPort[pID]
419 mutex.Unlock()
Rohan Agrawalda5e0b22020-05-20 11:10:26 +0000420 metricNames := StatMgr.Device.metrics.GetSubscriberMetrics()
Naga Manjunath7615e552019-10-11 22:35:47 +0530421
Rohan Agrawalda5e0b22020-05-20 11:10:26 +0000422 var metrics []string
Kent Hagermane6ff1012020-07-14 15:07:53 -0400423 for metric := range metricNames {
424 if metricNames[metric].Enabled {
425 metrics = append(metrics, metric)
Naga Manjunath7615e552019-10-11 22:35:47 +0530426 }
427 }
Rohan Agrawalda5e0b22020-05-20 11:10:26 +0000428
429 for _, mName := range metrics {
430 switch mName {
431 case "rx_bytes":
432 ponval["RxBytes"] = float32(cm.RxBytes)
433 case "rx_packets":
434 ponval["RxPackets"] = float32(cm.RxPackets)
435 case "rx_ucast_packets":
436 ponval["RxUcastPackets"] = float32(cm.RxUcastPackets)
437 case "rx_mcast_packets":
438 ponval["RxMcastPackets"] = float32(cm.RxMcastPackets)
439 case "rx_bcast_packets":
440 ponval["RxBcastPackets"] = float32(cm.RxBcastPackets)
441 case "tx_bytes":
442 ponval["TxBytes"] = float32(cm.TxBytes)
443 case "tx_packets":
444 ponval["TxPackets"] = float32(cm.TxPackets)
445 case "tx_mcast_packets":
446 ponval["TxMcastPackets"] = float32(cm.TxMcastPackets)
447 case "tx_bcast_packets":
448 ponval["TxBcastPackets"] = float32(cm.TxBcastPackets)
449 }
450 }
451
Naga Manjunath7615e552019-10-11 22:35:47 +0530452 return ponval
453}
454
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000455// converGemStats will convert gem stats response to kpi context
456func (StatMgr *OpenOltStatisticsMgr) convertGemStats(gemStats *openolt.GemPortStatistics) map[string]float32 {
457 gemStatsVal := make(map[string]float32)
458 gemStatsVal[IntfID] = float32(gemStats.IntfId)
459 gemStatsVal[GemID] = float32(gemStats.GemportId)
460 gemStatsVal[RxPackets] = float32(gemStats.RxPackets)
461 gemStatsVal[RxBytes] = float32(gemStats.RxBytes)
462 gemStatsVal[TxPackets] = float32(gemStats.TxPackets)
463 gemStatsVal[TxBytes] = float32(gemStats.TxBytes)
464 return gemStatsVal
465}
466
467// convertONUStats will convert onu stats response to kpi context
468func (StatMgr *OpenOltStatisticsMgr) convertONUStats(onuStats *openolt.OnuStatistics) map[string]float32 {
469 onuStatsVal := make(map[string]float32)
470 onuStatsVal[IntfID] = float32(onuStats.IntfId)
471 onuStatsVal[OnuID] = float32(onuStats.OnuId)
472 onuStatsVal[PositiveDrift] = float32(onuStats.PositiveDrift)
473 onuStatsVal[NegativeDrift] = float32(onuStats.NegativeDrift)
474 onuStatsVal[DelimiterMissDetection] = float32(onuStats.DelimiterMissDetection)
475 onuStatsVal[BipErrors] = float32(onuStats.BipErrors)
476 onuStatsVal[BipUnits] = float32(onuStats.BipUnits)
477 onuStatsVal[FecCorrectedSymbols] = float32(onuStats.FecCorrectedSymbols)
478 onuStatsVal[FecCodewordsCorrected] = float32(onuStats.FecCodewordsCorrected)
479 onuStatsVal[fecCodewordsUncorrectable] = float32(onuStats.FecCodewordsUncorrectable)
480 onuStatsVal[FecCodewords] = float32(onuStats.FecCodewords)
481 onuStatsVal[FecCorrectedUnits] = float32(onuStats.FecCorrectedUnits)
482 onuStatsVal[XGEMKeyErrors] = float32(onuStats.XgemKeyErrors)
483 onuStatsVal[XGEMLoss] = float32(onuStats.XgemLoss)
484 onuStatsVal[RxPloamsError] = float32(onuStats.RxPloamsError)
485 onuStatsVal[RxPloamsNonIdle] = float32(onuStats.RxPloamsNonIdle)
486 onuStatsVal[RxOmci] = float32(onuStats.RxOmci)
487 onuStatsVal[RxOmciPacketsCrcError] = float32(onuStats.RxOmciPacketsCrcError)
488 onuStatsVal[RxBytes] = float32(onuStats.RxBytes)
489 onuStatsVal[RxPackets] = float32(onuStats.RxPackets)
490 onuStatsVal[TxBytes] = float32(onuStats.TxBytes)
491 onuStatsVal[TxPackets] = float32(onuStats.TxPackets)
492 onuStatsVal[BerReported] = float32(onuStats.BerReported)
493 onuStatsVal[LcdgErrors] = float32(onuStats.LcdgErrors)
494 onuStatsVal[RdiErrors] = float32(onuStats.RdiErrors)
495 return onuStatsVal
496}
497
498// collectOnuStats will collect the onu metrics
499func (StatMgr *OpenOltStatisticsMgr) collectOnuStats(ctx context.Context, onuGemInfo rsrcMgr.OnuGemInfo) {
500 onu := &openolt.Onu{IntfId: onuGemInfo.IntfID, OnuId: onuGemInfo.OnuID}
501 logger.Debugw(ctx, "pulling-onu-stats", log.Fields{"IntfID": onuGemInfo.IntfID, "OnuID": onuGemInfo.OnuID})
502 if stats, err := StatMgr.Device.Client.GetOnuStatistics(context.Background(), onu); err == nil {
503 onuStats <- stats
504 } else {
505 logger.Errorw(ctx, "error-while-getting-onu-stats-for-onu", log.Fields{"IntfID": onuGemInfo.IntfID, "OnuID": onuGemInfo.OnuID, "err": err})
506 }
507}
508
509// collectOnuAndGemStats will collect both onu and gem metrics
510func (StatMgr *OpenOltStatisticsMgr) collectOnuAndGemStats(ctx context.Context, onuGemInfo []rsrcMgr.OnuGemInfo) {
511 if !StatMgr.Device.openOLT.enableONUStats && !StatMgr.Device.openOLT.enableGemStats {
512 return
513 }
514
515 for _, onuInfo := range onuGemInfo {
516 if StatMgr.Device.openOLT.enableONUStats {
517 go StatMgr.collectOnuStats(ctx, onuInfo)
518 }
519 if StatMgr.Device.openOLT.enableGemStats {
520 go StatMgr.collectGemStats(ctx, onuInfo)
521 }
522 }
523}
524
525// collectGemStats will collect gem metrics
526func (StatMgr *OpenOltStatisticsMgr) collectGemStats(ctx context.Context, onuGemInfo rsrcMgr.OnuGemInfo) {
527 for _, gem := range onuGemInfo.GemPorts {
528 logger.Debugw(ctx, "pulling-gem-stats", log.Fields{"IntfID": onuGemInfo.IntfID, "OnuID": onuGemInfo.OnuID, "GemID": gem})
529 onuPacket := &openolt.OnuPacket{IntfId: onuGemInfo.IntfID, OnuId: onuGemInfo.OnuID, GemportId: gem}
530 if stats, err := StatMgr.Device.Client.GetGemPortStatistics(context.Background(), onuPacket); err == nil {
531 gemStats <- stats
532 } else {
533 logger.Errorw(ctx, "error-while-getting-gem-stats-for-onu",
534 log.Fields{"IntfID": onuGemInfo.IntfID, "OnuID": onuGemInfo.OnuID, "GemID": gem, "err": err})
535 }
536 }
537}
538
539// publishGemStats will publish the gem metrics
540func (StatMgr *OpenOltStatisticsMgr) publishGemStats() {
541 for {
542 statValue := StatMgr.convertGemStats(<-gemStats)
543 StatMgr.publishMetrics(context.Background(), GEMStats, statValue, &voltha.Port{Label: "GEM"}, StatMgr.Device.device.Id, StatMgr.Device.device.Type)
544 }
545}
546
547// publishOnuStats will publish the onu metrics
548func (StatMgr *OpenOltStatisticsMgr) publishOnuStats() {
549 for {
550 statValue := StatMgr.convertONUStats(<-onuStats)
551 StatMgr.publishMetrics(context.Background(), ONUStats, statValue, &voltha.Port{Label: "ONU"}, StatMgr.Device.device.Id, StatMgr.Device.device.Type)
552 }
553}
554
555// publishMetrics will publish the pon port metrics
kesavand62126212021-01-12 04:56:06 -0500556func (StatMgr *OpenOltStatisticsMgr) publishMetrics(ctx context.Context, statType string, val map[string]float32,
Girish Gowdra34815db2020-05-11 17:18:04 -0700557 port *voltha.Port, devID string, devType string) {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000558 logger.Debugw(ctx, "publish-metrics",
Shrey Baid26912972020-04-16 21:02:31 +0530559 log.Fields{
560 "port": port.Label,
561 "metrics": val})
Naga Manjunath7615e552019-10-11 22:35:47 +0530562
563 var metricInfo voltha.MetricInformation
564 var ke voltha.KpiEvent2
Esin Karamanccb714b2019-11-29 15:02:06 +0000565 var volthaEventSubCatgry voltha.EventSubCategory_Types
Girish Gowdra34815db2020-05-11 17:18:04 -0700566 metricsContext := make(map[string]string)
567 metricsContext["oltid"] = devID
568 metricsContext["devicetype"] = devType
569 metricsContext["portlabel"] = port.Label
Naga Manjunath7615e552019-10-11 22:35:47 +0530570
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000571 if statType == NNIStats {
Naga Manjunath7615e552019-10-11 22:35:47 +0530572 volthaEventSubCatgry = voltha.EventSubCategory_NNI
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000573 } else if statType == PONStats {
Naga Manjunath7615e552019-10-11 22:35:47 +0530574 volthaEventSubCatgry = voltha.EventSubCategory_PON
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000575 } else if statType == GEMStats || statType == ONUStats {
576 volthaEventSubCatgry = voltha.EventSubCategory_ONT
Naga Manjunath7615e552019-10-11 22:35:47 +0530577 }
578
579 raisedTs := time.Now().UnixNano()
580 mmd := voltha.MetricMetaData{
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000581 Title: statType,
Naga Manjunath7615e552019-10-11 22:35:47 +0530582 Ts: float64(raisedTs),
Girish Gowdra34815db2020-05-11 17:18:04 -0700583 Context: metricsContext,
Naga Manjunath7615e552019-10-11 22:35:47 +0530584 DeviceId: devID,
585 }
586
587 metricInfo.Metadata = &mmd
588 metricInfo.Metrics = val
589
590 ke.SliceData = []*voltha.MetricInformation{&metricInfo}
591 ke.Type = voltha.KpiEventType_slice
592 ke.Ts = float64(time.Now().UnixNano())
593
Neha Sharma96b7bf22020-06-15 10:37:32 +0000594 if err := StatMgr.Device.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, volthaEventSubCatgry, raisedTs); err != nil {
Gamze Abakafcbd6e72020-12-17 13:25:16 +0000595 logger.Errorw(ctx, "failed-to-send-stats", log.Fields{"err": err})
Naga Manjunath7615e552019-10-11 22:35:47 +0530596 }
Naga Manjunath7615e552019-10-11 22:35:47 +0530597}
598
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700599// PortStatisticsIndication handles the port statistics indication
Neha Sharma96b7bf22020-06-15 10:37:32 +0000600func (StatMgr *OpenOltStatisticsMgr) PortStatisticsIndication(ctx context.Context, PortStats *openolt.PortStatistics, NumPonPorts uint32) {
601 StatMgr.PortsStatisticsKpis(ctx, PortStats, NumPonPorts)
602 logger.Debugw(ctx, "received-port-stats-indication", log.Fields{"port-stats": PortStats})
kesavand62126212021-01-12 04:56:06 -0500603 //Indicate that PortStatisticsIndication is handled
604 //PortStats.IntfId is actually the port number
605 StatMgr.processStatIndication(ctx, portStatsType, PortStats.IntfId)
Abhilash S.L765ad002019-04-24 16:40:57 +0530606 // TODO send stats to core topic to the voltha kafka or a different kafka ?
607}
608
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700609// FlowStatisticsIndication to be implemented
Neha Sharma96b7bf22020-06-15 10:37:32 +0000610func FlowStatisticsIndication(ctx context.Context, self, FlowStats *openolt.FlowStatistics) {
611 logger.Debugw(ctx, "flow-stats-collected", log.Fields{"flow-stats": FlowStats})
Abhilash S.L765ad002019-04-24 16:40:57 +0530612 //TODO send to kafka ?
613}
614
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700615// PortsStatisticsKpis map the port stats values into a dictionary, creates the kpiEvent and then publish to Kafka
Neha Sharma96b7bf22020-06-15 10:37:32 +0000616func (StatMgr *OpenOltStatisticsMgr) PortsStatisticsKpis(ctx context.Context, PortStats *openolt.PortStatistics, NumPonPorts uint32) {
Abhilash S.L765ad002019-04-24 16:40:57 +0530617
618 /*map the port stats values into a dictionary
619 Create a kpoEvent and publish to Kafka
620
621 :param port_stats:
622 :return:
623 */
624 //var err error
625 IntfID := PortStats.IntfId
626
Naga Manjunath7615e552019-10-11 22:35:47 +0530627 if (IntfIDToPortNo(1, voltha.Port_ETHERNET_NNI) < IntfID) &&
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700628 (IntfID < IntfIDToPortNo(4, voltha.Port_ETHERNET_NNI)) {
Abhilash S.L765ad002019-04-24 16:40:57 +0530629 /*
630 for this release we are only interested in the first NNI for
631 Northbound.
632 we are not using the other 3
633 */
634 return
Naga Manjunath7615e552019-10-11 22:35:47 +0530635 } else if IntfIDToPortNo(0, voltha.Port_ETHERNET_NNI) == IntfID {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700636
Naga Manjunath7615e552019-10-11 22:35:47 +0530637 var portNNIStat NniPort
638 portNNIStat.IntfID = IntfID
639 portNNIStat.PortNum = uint32(0)
640 portNNIStat.RxBytes = PortStats.RxBytes
641 portNNIStat.RxPackets = PortStats.RxPackets
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000642 portNNIStat.RxUcastPackets = PortStats.RxUcastPackets
Naga Manjunath7615e552019-10-11 22:35:47 +0530643 portNNIStat.RxMcastPackets = PortStats.RxMcastPackets
644 portNNIStat.RxBcastPackets = PortStats.RxBcastPackets
645 portNNIStat.TxBytes = PortStats.TxBytes
646 portNNIStat.TxPackets = PortStats.TxPackets
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000647 portNNIStat.TxUcastPackets = PortStats.TxUcastPackets
Naga Manjunath7615e552019-10-11 22:35:47 +0530648 portNNIStat.TxMcastPackets = PortStats.TxMcastPackets
649 portNNIStat.TxBcastPackets = PortStats.TxBcastPackets
650 mutex.Lock()
651 StatMgr.NorthBoundPort[0] = &portNNIStat
652 mutex.Unlock()
Neha Sharma96b7bf22020-06-15 10:37:32 +0000653 logger.Debugw(ctx, "received-nni-stats", log.Fields{"nni-stats": StatMgr.NorthBoundPort})
Naga Manjunath7615e552019-10-11 22:35:47 +0530654 }
655 for i := uint32(0); i < NumPonPorts; i++ {
656
657 if IntfIDToPortNo(i, voltha.Port_PON_OLT) == IntfID {
658 var portPonStat PonPort
659 portPonStat.IntfID = IntfID
660 portPonStat.PortNum = i
661 portPonStat.PONID = i
662 portPonStat.RxBytes = PortStats.RxBytes
663 portPonStat.RxPackets = PortStats.RxPackets
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000664 portPonStat.RxUcastPackets = PortStats.RxUcastPackets
Naga Manjunath7615e552019-10-11 22:35:47 +0530665 portPonStat.RxMcastPackets = PortStats.RxMcastPackets
666 portPonStat.RxBcastPackets = PortStats.RxBcastPackets
667 portPonStat.TxBytes = PortStats.TxBytes
668 portPonStat.TxPackets = PortStats.TxPackets
Dileep Kuchhangi52cfbe12020-01-15 20:16:21 +0000669 portPonStat.TxUcastPackets = PortStats.TxUcastPackets
Naga Manjunath7615e552019-10-11 22:35:47 +0530670 portPonStat.TxMcastPackets = PortStats.TxMcastPackets
671 portPonStat.TxBcastPackets = PortStats.TxBcastPackets
672 mutex.Lock()
673 StatMgr.SouthBoundPort[i] = &portPonStat
674 mutex.Unlock()
Neha Sharma96b7bf22020-06-15 10:37:32 +0000675 logger.Debugw(ctx, "received-pon-stats-for-port", log.Fields{"port-pon-stats": portPonStat})
Naga Manjunath7615e552019-10-11 22:35:47 +0530676 }
677 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700678
679 /*
680 Based upon the intf_id map to an nni port or a pon port
681 the intf_id is the key to the north or south bound collections
682
683 Based upon the intf_id the port object (nni_port or pon_port) will
684 have its data attr. updated by the current dataset collected.
685
686 For prefixing the rule is currently to use the port number and not the intf_id
687 */
688 //FIXME : Just use first NNI for now
689 /* TODO should the data be marshaled before sending it ?
690 if IntfID == IntfIdToPortNo(0, voltha.Port_ETHERNET_NNI) {
691 //NNI port (just the first one)
692 err = UpdatePortObjectKpiData(StatMgr.NorthBoundPorts[PortStats.IntfID], PMData)
693 } else {
694 //PON ports
695 err = UpdatePortObjectKpiData(SouthboundPorts[PortStats.IntfID], PMData)
696 }
697 if (err != nil) {
Neha Sharma96b7bf22020-06-15 10:37:32 +0000698 logger.Error(ctx, "Error publishing statistics data")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700699 }
700 */
701
Abhilash S.L765ad002019-04-24 16:40:57 +0530702}
kesavand62126212021-01-12 04:56:06 -0500703
704func (StatMgr *OpenOltStatisticsMgr) updateGetOltPortCountersResponse(ctx context.Context, singleValResp *extension.SingleGetValueResponse, stats map[string]float32) {
705
706 metrics := singleValResp.GetResponse().GetPortCoutners()
707 metrics.TxBytes = uint64(stats["TxBytes"])
708 metrics.RxBytes = uint64(stats["RxBytes"])
709 metrics.TxPackets = uint64(stats["TxPackets"])
710 metrics.RxPackets = uint64(stats["RxPackets"])
711 metrics.TxErrorPackets = uint64(stats["TxErrorPackets"])
712 metrics.RxErrorPackets = uint64(stats["RxErrorPackets"])
713 metrics.TxBcastPackets = uint64(stats["TxBcastPackets"])
714 metrics.RxBcastPackets = uint64(stats["RxBcastPackets"])
715 metrics.TxUcastPackets = uint64(stats["TxUcastPackets"])
716 metrics.RxUcastPackets = uint64(stats["RxUcastPackets"])
717 metrics.TxMcastPackets = uint64(stats["TxMcastPackets"])
718 metrics.RxMcastPackets = uint64(stats["RxMcastPackets"])
719
720 singleValResp.Response.Status = extension.GetValueResponse_OK
721 logger.Debugw(ctx, "updateGetOltPortCountersResponse", log.Fields{"resp": singleValResp})
722}
723
724//RegisterForStatIndication registers ch as a channel on which indication is sent when statistics of type t is received
725func (StatMgr *OpenOltStatisticsMgr) RegisterForStatIndication(ctx context.Context, t StatType, ch chan bool, portNo uint32, portType extension.GetOltPortCounters_PortType) {
726 statInd := statRegInfo{
727 chn: ch,
728 portNo: portNo,
729 portType: portType,
730 }
731
732 logger.Debugf(ctx, "RegisterForStatIndication stat type %v portno %v porttype %v chan %v", t, portNo, portType, ch)
733 StatMgr.statIndListnerMu.Lock()
734 StatMgr.statIndListners[t].PushBack(statInd)
735 StatMgr.statIndListnerMu.Unlock()
736
737}
738
739//DeRegisterFromStatIndication removes the previously registered channel ch for type t of statistics
740func (StatMgr *OpenOltStatisticsMgr) DeRegisterFromStatIndication(ctx context.Context, t StatType, ch chan bool) {
741 StatMgr.statIndListnerMu.Lock()
742 defer StatMgr.statIndListnerMu.Unlock()
743
744 for e := StatMgr.statIndListners[t].Front(); e != nil; e = e.Next() {
745 statInd := e.Value.(statRegInfo)
746 if statInd.chn == ch {
747 StatMgr.statIndListners[t].Remove(e)
748 return
749 }
750 }
751}
752
753func (StatMgr *OpenOltStatisticsMgr) processStatIndication(ctx context.Context, t StatType, portNo uint32) {
754 var deRegList []*list.Element
755 var statInd statRegInfo
756
757 StatMgr.statIndListnerMu.Lock()
758 defer StatMgr.statIndListnerMu.Unlock()
759
760 if StatMgr.statIndListners[t] == nil || StatMgr.statIndListners[t].Len() == 0 {
761 logger.Debugf(ctx, "processStatIndication %v list is empty ", t)
762 return
763 }
764
765 for e := StatMgr.statIndListners[t].Front(); e != nil; e = e.Next() {
766 statInd = e.Value.(statRegInfo)
767 if statInd.portNo != portNo {
768 fmt.Printf("Skipping %v\n", e.Value)
769 continue
770 }
771 // message sent
772 statInd.chn <- true
773 deRegList = append(deRegList, e)
774
775 }
776 for _, e := range deRegList {
777 StatMgr.statIndListners[t].Remove(e)
778 }
779
780}