blob: 972670f663ea06c8cfdb422114d949e83423f6f2 [file] [log] [blame]
Holger Hildebrandtfa074992020-03-27 15:42:06 +00001/*
2 * Copyright 2020-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
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +000017//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
Holger Hildebrandtfa074992020-03-27 15:42:06 +000019
20import (
21 "container/list"
22 "context"
23 "encoding/binary"
24 "encoding/hex"
25 "errors"
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +000026 "strconv"
Holger Hildebrandtfa074992020-03-27 15:42:06 +000027 "sync"
28
29 //"time"
30
31 "github.com/google/gopacket"
32 // TODO!!! Some references could be resolved auto, but some need specific context ....
33 gp "github.com/google/gopacket"
34
35 "github.com/opencord/omci-lib-go"
36 me "github.com/opencord/omci-lib-go/generated"
37 "github.com/opencord/voltha-lib-go/v3/pkg/adapters/adapterif"
38
39 //"github.com/opencord/voltha-lib-go/v3/pkg/kafka"
40 "github.com/opencord/voltha-lib-go/v3/pkg/log"
41 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
42 //"github.com/opencord/voltha-protos/v3/go/openflow_13"
43 //"github.com/opencord/voltha-protos/v3/go/voltha"
44)
45
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +000046// ### OMCI related definitions - retrieved from Python adapter code/trace ####
Holger Hildebrandtfa074992020-03-27 15:42:06 +000047const ConstDefaultOmciTimeout = 10 // ( 3 ?) Seconds
48
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +000049const galEthernetEID = uint16(1)
50const maxGemPayloadSize = uint16(48)
51const connectivityModeValue = uint8(5)
52const defaultTPID = uint16(0x8100)
53const broadComDefaultVID = uint16(4091)
54const macBridgeServiceProfileEID = uint16(0x201) // TODO: most all these need better definition or tuning
55const ieeeMapperServiceProfileEID = uint16(0x8001)
56const macBridgePortAniEID = uint16(0x2102)
57
58// ### OMCI related definitions - end
59
Holger Hildebrandtfa074992020-03-27 15:42:06 +000060//CallbackPair to be used for ReceiveCallback init
61type CallbackPair struct {
62 cbKey uint16
63 cbFunction func(*omci.OMCI, *gp.Packet) error
64}
65
66type omciTransferStructure struct {
67 txFrame []byte
68 timeout int
69 retry int
70 highPrio bool
71}
72
73//OmciCC structure holds information needed for OMCI communication (to/from OLT Adapter)
74type OmciCC struct {
75 enabled bool
76 pOnuDeviceEntry *OnuDeviceEntry
77 deviceID string
78 pBaseDeviceHandler *DeviceHandler
79 coreProxy adapterif.CoreProxy
80 adapterProxy adapterif.AdapterProxy
81 supportExtMsg bool
82 //txRequest
83 //rxResponse
84 //pendingRequest
85 txFrames, txOnuFrames uint32
86 rxFrames, rxOnuFrames, rxOnuDiscards uint32
87
88 // OMCI params
89 mutexTid sync.Mutex
90 tid uint16
91 mutexHpTid sync.Mutex
92 hpTid uint16
93 uploadSequNo uint16
94 uploadNoOfCmds uint16
95
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +000096 mutexTxQueue sync.Mutex
97 txQueue *list.List
98 mutexRxSchedMap sync.Mutex
99 rxSchedulerMap map[uint16]func(*omci.OMCI, *gp.Packet) error
100 pLastTxMeInstance *me.ManagedEntity
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000101}
102
103//NewOmciCC constructor returns a new instance of a OmciCC
104//mib_db (as well as not inluded alarm_db not really used in this code? VERIFY!!)
105func NewOmciCC(ctx context.Context, onu_device_entry *OnuDeviceEntry,
106 device_id string, device_handler *DeviceHandler,
107 core_proxy adapterif.CoreProxy, adapter_proxy adapterif.AdapterProxy) *OmciCC {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000108 logger.Infow("init-omciCC", log.Fields{"deviceId": device_id})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000109 var omciCC OmciCC
110 omciCC.enabled = false
111 omciCC.pOnuDeviceEntry = onu_device_entry
112 omciCC.deviceID = device_id
113 omciCC.pBaseDeviceHandler = device_handler
114 omciCC.coreProxy = core_proxy
115 omciCC.adapterProxy = adapter_proxy
116 omciCC.supportExtMsg = false
117 omciCC.txFrames = 0
118 omciCC.txOnuFrames = 0
119 omciCC.rxFrames = 0
120 omciCC.rxOnuFrames = 0
121 omciCC.rxOnuDiscards = 0
122 omciCC.tid = 0x1
123 omciCC.hpTid = 0x8000
124 omciCC.uploadSequNo = 0
125 omciCC.uploadNoOfCmds = 0
126
127 omciCC.txQueue = list.New()
128 omciCC.rxSchedulerMap = make(map[uint16]func(*omci.OMCI, *gp.Packet) error)
129
130 return &omciCC
131}
132
133// Rx handler for omci messages
134func (oo *OmciCC) ReceiveOnuMessage(ctx context.Context, omciMsg *omci.OMCI) error {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000135 logger.Debugw("rx-onu-autonomous-message", log.Fields{"omciMsgType": omciMsg.MessageType,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000136 "payload": hex.EncodeToString(omciMsg.Payload)})
137 /*
138 msgType = rxFrame.fields["message_type"] //assumed OmciOperationsValue
139 rxOnuFrames++
140
141 switch msgType {
142 case AlarmNotification:
143 {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000144 logger.Info("Unhandled: received-onu-alarm-message")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000145 // python code was:
146 //if msg_type == EntityOperations.AlarmNotification.value:
147 // topic = OMCI_CC.event_bus_topic(self._device_id, RxEvent.Alarm_Notification)
148 // self.reactor.callLater(0, self.event_bus.publish, topic, msg)
149 //
150 return errors.New("RxAlarmNotification unimplemented")
151 }
152 case AttributeValueChange:
153 {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000154 logger.Info("Unhandled: received-attribute-value-change")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000155 // python code was:
156 //elif msg_type == EntityOperations.AttributeValueChange.value:
157 // topic = OMCI_CC.event_bus_topic(self._device_id, RxEvent.AVC_Notification)
158 // self.reactor.callLater(0, self.event_bus.publish, topic, msg)
159 //
160 return errors.New("RxAttributeValueChange unimplemented")
161 }
162 case TestResult:
163 {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000164 logger.Info("Unhandled: received-test-result")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000165 // python code was:
166 //elif msg_type == EntityOperations.TestResult.value:
167 // topic = OMCI_CC.event_bus_topic(self._device_id, RxEvent.Test_Result)
168 // self.reactor.callLater(0, self.event_bus.publish, topic, msg)
169 //
170 return errors.New("RxTestResult unimplemented")
171 }
172 default:
173 {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000174 logger.Errorw("rx-onu-unsupported-autonomous-message", log.Fields{"msgType": msgType})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000175 rxOnuDiscards++
176 return errors.New("RxOnuMsgType unimplemented")
177 }
178 }
179 */
180 return errors.New("ReceiveOnuMessage unimplemented")
181}
182
183// Rx handler for onu messages
184// e.g. would call ReceiveOnuMessage() in case of TID=0 or Action=test ...
185func (oo *OmciCC) ReceiveMessage(ctx context.Context, rxMsg []byte) error {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000186 //logger.Debugw("cc-receive-omci-message", log.Fields{"RxOmciMessage-x2s": hex.EncodeToString(rxMsg)})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000187 if len(rxMsg) >= 44 { // then it should normally include the BaseFormat trailer Len
188 // NOTE: autocorrection only valid for OmciBaseFormat, which is not specifically verified here!!!
189 // (am extendedFormat message could be destroyed this way!)
190 trailerLenData := rxMsg[42:44]
191 trailerLen := binary.BigEndian.Uint16(trailerLenData)
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000192 logger.Infow("omci-received-trailer-len", log.Fields{"Length": trailerLen})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000193 if trailerLen != 40 { // invalid base Format entry -> autocorrect
194 binary.BigEndian.PutUint16(rxMsg[42:44], 40)
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000195 logger.Debug("cc-corrected-omci-message: trailer len inserted")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000196 }
197 } else {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000198 logger.Errorw("received omci-message to small for OmciBaseFormat - abort", log.Fields{"Length": len(rxMsg)})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000199 return errors.New("RxOmciMessage to small for BaseFormat")
200 }
201
202 packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
203 if packet == nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000204 logger.Error("omci-message could not be decoded")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000205 return errors.New("could not decode rxMsg as OMCI")
206 }
207 omciLayer := packet.Layer(omci.LayerTypeOMCI)
208 if omciLayer == nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000209 logger.Error("omci-message could not decode omci layer")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000210 return errors.New("could not decode omci layer")
211 }
212 omciMsg, ok := omciLayer.(*omci.OMCI)
213 if !ok {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000214 logger.Error("omci-message could not assign omci layer")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000215 return errors.New("could not assign omci layer")
216 }
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000217 logger.Debugw("omci-message-decoded:", log.Fields{"omciMsgType": omciMsg.MessageType,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000218 "transCorrId": omciMsg.TransactionID, "DeviceIdent": omciMsg.DeviceIdentifier})
219 if byte(omciMsg.MessageType) & ^me.AK == 0 {
220 // Not a response
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000221 logger.Debug("RxMsg is no Omci Response Message")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000222 if omciMsg.TransactionID == 0 {
223 return oo.ReceiveOnuMessage(ctx, omciMsg)
224 } else {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000225 logger.Errorw("Unexpected TransCorrId != 0 not accepted for autonomous messages",
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000226 log.Fields{"msgType": omciMsg.MessageType, "payload": hex.EncodeToString(omciMsg.Payload)})
227 return errors.New("Autonomous Omci Message with TranSCorrId != 0 not acccepted")
228 }
229 } else {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000230 logger.Debug("RxMsg is a Omci Response Message: try to schedule it to the requester")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000231 oo.mutexRxSchedMap.Lock()
232 rxCallback, ok := oo.rxSchedulerMap[omciMsg.TransactionID]
233 if ok && rxCallback != nil {
234 //disadvantage of decoupling: error verification made difficult, but anyway the question is
235 // how to react on erroneous frame reception, maybe can simply be ignored
236 go rxCallback(omciMsg, &packet)
237 // having posted the response the request is regarded as 'done'
238 delete(oo.rxSchedulerMap, omciMsg.TransactionID)
239 oo.mutexRxSchedMap.Unlock()
240 } else {
241 oo.mutexRxSchedMap.Unlock()
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000242 logger.Error("omci-message-response for not registered transCorrId")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000243 return errors.New("could not find registered response handler tor transCorrId")
244 }
245 }
246
247 return nil
248 /* py code was:
249 Receive and OMCI message from the proxy channel to the OLT.
250
251 Call this from your ONU Adapter on a new OMCI Rx on the proxy channel
252 :param msg: (str) OMCI binary message (used as input to Scapy packet decoder)
253 """
254 if not self.enabled:
255 return
256
257 try:
258 now = arrow.utcnow()
259 d = None
260
261 # NOTE: Since we may need to do an independent ME map on a per-ONU basis
262 # save the current value of the entity_id_to_class_map, then
263 # replace it with our custom one before decode, and then finally
264 # restore it later. Tried other ways but really made the code messy.
265 saved_me_map = omci_entities.entity_id_to_class_map
266 omci_entities.entity_id_to_class_map = self._me_map
267
268 try:
269 rx_frame = msg if isinstance(msg, OmciFrame) else OmciFrame(msg)
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000270 self.logger.debug('recv-omci-msg', omci_msg=hexlify(msg))
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000271 except KeyError as e:
272 # Unknown, Unsupported, or vendor-specific ME. Key is the unknown classID
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000273 self.logger.debug('frame-decode-key-error', omci_msg=hexlify(msg), e=e)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000274 rx_frame = self._decode_unknown_me(msg)
275 self._rx_unknown_me += 1
276
277 except Exception as e:
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000278 self.logger.exception('frame-decode', omci_msg=hexlify(msg), e=e)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000279 return
280
281 finally:
282 omci_entities.entity_id_to_class_map = saved_me_map # Always restore it.
283
284 rx_tid = rx_frame.fields['transaction_id']
285 msg_type = rx_frame.fields['message_type']
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000286 self.logger.debug('Received message for rx_tid', rx_tid = rx_tid, msg_type = msg_type)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000287 # Filter the Test Result frame and route through receive onu
288 # message method.
289 if rx_tid == 0 or msg_type == EntityOperations.TestResult.value:
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000290 self.logger.debug('Receive ONU message', rx_tid=0)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000291 return self._receive_onu_message(rx_frame)
292
293 # Previously unreachable if this is the very first round-trip Rx or we
294 # have been running consecutive errors
295 if self._rx_frames == 0 or self._consecutive_errors != 0:
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000296 self.logger.debug('Consecutive errors for rx', err = self._consecutive_errors)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000297 self.reactor.callLater(0, self._publish_connectivity_event, True)
298
299 self._rx_frames += 1
300 self._consecutive_errors = 0
301
302 try:
303 high_priority = self._tid_is_high_priority(rx_tid)
304 index = self._get_priority_index(high_priority)
305
306 # (timestamp, defer, frame, timeout, retry, delayedCall)
307 last_tx_tuple = self._tx_request[index]
308
309 if last_tx_tuple is None or \
310 last_tx_tuple[OMCI_CC.REQUEST_FRAME].fields.get('transaction_id') != rx_tid:
311 # Possible late Rx on a message that timed-out
312 if last_tx_tuple:
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000313 self.logger.debug('Unknown message', rx_tid=rx_tid,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000314 tx_id=last_tx_tuple[OMCI_CC.REQUEST_FRAME].fields.get('transaction_id'))
315 self._rx_unknown_tid += 1
316 self._rx_late += 1
317 return
318
319 ts, d, tx_frame, timeout, retry, dc = last_tx_tuple
320 if dc is not None and not dc.cancelled and not dc.called:
321 dc.cancel()
322
323 _secs = self._update_rx_tx_stats(now, ts)
324
325 # Late arrival already serviced by a timeout?
326 if d.called:
327 self._rx_late += 1
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000328 self.logger.debug('Serviced by timeout. Late arrival', rx_late = self._rx_late)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000329 return
330
331 except Exception as e:
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000332 self.logger.exception('frame-match', msg=hexlify(msg), e=e)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000333 if d is not None:
334 return d.errback(failure.Failure(e))
335 return
336
337 # Publish Rx event to listeners in a different task
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000338 self.logger.debug('Publish rx event', rx_tid = rx_tid,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000339 tx_tid = tx_frame.fields['transaction_id'])
340 reactor.callLater(0, self._publish_rx_frame, tx_frame, rx_frame)
341
342 # begin success callback chain (will cancel timeout and queue next Tx message)
343 self._rx_response[index] = rx_frame
344 d.callback(rx_frame)
345
346 except Exception as e:
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000347 self.logger.exception('rx-msg', e=e)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000348 */
349}
350
351func (oo *OmciCC) PublishRxResponseFrame(ctx context.Context, txFrame []byte, rxFrame []byte) error {
352 return errors.New("PublishRxResponseFrame unimplemented")
353 /*
354 def _publish_rx_frame(self, tx_frame, rx_frame):
355 */
356}
357
358//Queue the OMCI Frame for a transmit to the ONU via the proxy_channel
359func (oo *OmciCC) Send(ctx context.Context, txFrame []byte, timeout int, retry int, highPrio bool,
360 receiveCallbackPair CallbackPair) error {
361
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000362 logger.Debugw("register-response-callback:", log.Fields{"for TansCorrId": receiveCallbackPair.cbKey})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000363 // it could be checked, if the callback keay is already registered - but simply overwrite may be acceptable ...
364 oo.mutexRxSchedMap.Lock()
365 oo.rxSchedulerMap[receiveCallbackPair.cbKey] = receiveCallbackPair.cbFunction
366 oo.mutexRxSchedMap.Unlock()
367
368 //just use a simple list for starting - might need some more effort, especially for multi source write access
369 omciTxRequest := omciTransferStructure{
370 txFrame,
371 timeout,
372 retry,
373 highPrio,
374 }
375 oo.mutexTxQueue.Lock()
376 oo.txQueue.PushBack(omciTxRequest) // enqueue
377 oo.mutexTxQueue.Unlock()
378
379 // for first test just bypass and send directly:
380 go oo.sendNextRequest(ctx)
381 return nil
382}
383
384//Pull next tx request and send it
385func (oo *OmciCC) sendNextRequest(ctx context.Context) error {
386 // return errors.New("sendNextRequest unimplemented")
387
388 // just try to get something transferred !!
389 // avoid accessing the txQueue from parallel send requests
390 // block parallel omci send requests at least until SendIAP is 'committed'
391 // that should be feasible for an onu instance as on OMCI anyway window size 1 is assumed
392 oo.mutexTxQueue.Lock()
393 for oo.txQueue.Len() > 0 {
394 queueElement := oo.txQueue.Front() // First element
395 omciTxRequest := queueElement.Value.(omciTransferStructure)
396 /* compare olt device handler code:
397 func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000398 logger.Debugw("omci indication", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000399 var deviceType string
400 var deviceID string
401 var proxyDeviceID string
402
403 onuKey := dh.formOnuKey(omciInd.IntfId, omciInd.OnuId)
404
405 if onuInCache, ok := dh.onus.Load(onuKey); !ok {
406
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000407 logger.Debugw("omci indication for a device not in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000408 ponPort := IntfIDToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
409 kwargs := make(map[string]interface{})
410 kwargs["onu_id"] = omciInd.OnuId
411 kwargs["parent_port_no"] = ponPort
412
413 onuDevice, err := dh.coreProxy.GetChildDevice(context.TODO(), dh.device.Id, kwargs)
414 if err != nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000415 logger.Errorw("onu not found", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId, "error": err})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000416 return
417 }
418 deviceType = onuDevice.Type
419 deviceID = onuDevice.Id
420 proxyDeviceID = onuDevice.ProxyAddress.DeviceId
421 //if not exist in cache, then add to cache.
422 dh.onus.Store(onuKey, NewOnuDevice(deviceID, deviceType, onuDevice.SerialNumber, omciInd.OnuId, omciInd.IntfId, proxyDeviceID))
423 } else {
424 //found in cache
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000425 logger.Debugw("omci indication for a device in cache.", log.Fields{"intfID": omciInd.IntfId, "onuID": omciInd.OnuId})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000426 deviceType = onuInCache.(*OnuDevice).deviceType
427 deviceID = onuInCache.(*OnuDevice).deviceID
428 proxyDeviceID = onuInCache.(*OnuDevice).proxyDeviceID
429 }
430 */
431 /* and compare onu_adapter py code:
432 omci_msg = InterAdapterOmciMessage(
433 message=bytes(frame),
434 proxy_address=self._proxy_address,
435 connect_status=self._device.connect_status)
436
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000437 self.logger.debug('sent-omci-msg', tid=tx_tid, omci_msg=hexlify(bytes(frame)))
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000438
439 yield self._adapter_proxy.send_inter_adapter_message(
440 msg=omci_msg,
441 type=InterAdapterMessageType.OMCI_REQUEST,
442 from_adapter=self._device.type,
443 to_adapter=self._proxy_address.device_type,
444 to_device_id=self._device_id,
445 proxy_device_id=self._proxy_address.device_id
446 )
447 */
448 device, err := oo.coreProxy.GetDevice(ctx,
449 oo.pBaseDeviceHandler.deviceID, oo.deviceID) //parent, child
450 if err != nil || device == nil {
451 /*TODO: needs to handle error scenarios */
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000452 logger.Errorw("Failed to fetch device", log.Fields{"err": err, "ParentId": oo.pBaseDeviceHandler.deviceID,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000453 "ChildId": oo.deviceID})
454 return errors.New("failed to fetch device")
455 }
456
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000457 logger.Debugw("omci-message-sending", log.Fields{"fromDeviceType": oo.pBaseDeviceHandler.DeviceType,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000458 "toDeviceType": oo.pBaseDeviceHandler.ProxyAddressType,
459 "onuDeviceID": oo.deviceID, "proxyDeviceID": oo.pBaseDeviceHandler.ProxyAddressID})
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000460 logger.Debugw("omci-message-to-send:",
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000461 log.Fields{"TxOmciMessage": hex.EncodeToString(omciTxRequest.txFrame)})
462
463 omciMsg := &ic.InterAdapterOmciMessage{Message: omciTxRequest.txFrame}
464 if sendErr := oo.adapterProxy.SendInterAdapterMessage(context.Background(), omciMsg,
465 ic.InterAdapterMessageType_OMCI_REQUEST,
466 //fromType,toType,toDevId, ProxyDevId
467 oo.pBaseDeviceHandler.DeviceType, oo.pBaseDeviceHandler.ProxyAddressType,
468 oo.deviceID, oo.pBaseDeviceHandler.ProxyAddressID, ""); sendErr != nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000469 logger.Errorw("send omci request error", log.Fields{"error": sendErr})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000470 return sendErr
471 }
472 oo.txQueue.Remove(queueElement) // Dequeue
473 }
474 oo.mutexTxQueue.Unlock()
475 return nil
476}
477
478func (oo *OmciCC) GetNextTid(highPriority bool) uint16 {
479 var next uint16
480 if highPriority {
481 oo.mutexTid.Lock()
482 next = oo.hpTid
483 oo.hpTid += 1
484 if oo.hpTid < 0x8000 {
485 oo.hpTid = 0x8000
486 }
487 oo.mutexTid.Unlock()
488 } else {
489 oo.mutexHpTid.Lock()
490 next = oo.tid
491 oo.tid += 1
492 if oo.tid >= 0x8000 {
493 oo.tid = 1
494 }
495 oo.mutexHpTid.Unlock()
496 }
497 return next
498}
499
500// ###################################################################################
501// # utility methods provided to work on OMCI messages
502func serialize(msgType omci.MessageType, request gopacket.SerializableLayer, tid uint16) ([]byte, error) {
503 omciLayer := &omci.OMCI{
504 TransactionID: tid,
505 MessageType: msgType,
506 }
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +0000507 return serializeOmciLayer(omciLayer, request)
508}
509
510func serializeOmciLayer(a_omciLayer *omci.OMCI, a_request gopacket.SerializableLayer) ([]byte, error) {
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000511 var options gopacket.SerializeOptions
512 options.FixLengths = true
513
514 buffer := gopacket.NewSerializeBuffer()
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +0000515 err := gopacket.SerializeLayers(buffer, options, a_omciLayer, a_request)
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000516 if err != nil {
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +0000517 logger.Errorw("Could not create goPacket Omci serial buffer", log.Fields{"Err": err})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000518 return nil, err
519 }
520 return buffer.Bytes(), nil
521}
522
523func hexEncode(omciPkt []byte) ([]byte, error) {
524 dst := make([]byte, hex.EncodedLen(len(omciPkt)))
525 hex.Encode(dst, omciPkt)
526 return dst, nil
527}
528
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000529//supply a response handler for the MibSync omci response messages
530func (oo *OmciCC) receiveMibSyncResponse(omciMsg *omci.OMCI, packet *gp.Packet) error {
531
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000532 logger.Debugw("mib-sync-omci-message-response received:", log.Fields{"omciMsgType": omciMsg.MessageType,
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000533 "transCorrId": omciMsg.TransactionID, "deviceId": oo.deviceID})
534
535 if oo.pOnuDeviceEntry == nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000536 logger.Error("Abort Receive MibSync OMCI, DeviceEntryPointer is nil")
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000537 return errors.New("DeviceEntryPointer is nil")
538 }
539
540 // no further test on SeqNo is done here, assignment from rxScheduler is trusted
541 // MibSync responses are simply transferred via deviceEntry to MibSync, no specific analysis here
542 mibSyncMsg := Message{
543 Type: OMCI,
544 Data: OmciMessage{
545 OmciMsg: omciMsg,
546 OmciPacket: packet,
547 },
548 }
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000549 //logger.Debugw("Message to be sent into channel:", log.Fields{"mibSyncMsg": mibSyncMsg})
Holger Hildebrandt9ac0d0f2020-05-13 11:22:02 +0000550 (*oo.pOnuDeviceEntry).pMibUploadFsm.commChan <- mibSyncMsg
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000551
552 return nil
553}
554
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +0000555//supply a response handler for the MibDownload omci response messages
556func (oo *OmciCC) ReceiveMibDownloadResponse(omciMsg *omci.OMCI, packet *gp.Packet) error {
557
558 logger.Debugw("mib-download-omci-message-response received:", log.Fields{"omciMsgType": omciMsg.MessageType,
559 "transCorrId": omciMsg.TransactionID, "deviceId": oo.deviceID})
560
561 if oo.pOnuDeviceEntry == nil {
562 logger.Error("Abort Receive MibDownload OMCI response, DeviceEntryPointer is nil")
563 return errors.New("DeviceEntryPointer is nil")
564 }
565
566 // no further test on SeqNo is done here, assignment from rxScheduler is trusted
567 // MibDownload responses are simply transferred via deviceEntry to MibDownload, no specific analysis here
568 mibDlMsg := Message{
569 Type: OMCI,
570 Data: OmciMessage{
571 OmciMsg: omciMsg,
572 OmciPacket: packet,
573 },
574 }
575 (*oo.pOnuDeviceEntry).pMibDownloadFsm.commChan <- mibDlMsg
576
577 return nil
578}
579
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000580func (oo *OmciCC) sendMibReset(ctx context.Context, timeout int, highPrio bool) error {
581
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000582 logger.Debugw("send MibReset-msg to:", log.Fields{"deviceId": oo.deviceID})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000583 request := &omci.MibResetRequest{
584 MeBasePacket: omci.MeBasePacket{
585 EntityClass: me.OnuDataClassID,
586 },
587 }
588 tid := oo.GetNextTid(highPrio)
589 pkt, err := serialize(omci.MibResetRequestType, request, tid)
590 if err != nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000591 logger.Errorw("Cannot serialize MibResetRequest", log.Fields{"Err": err})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000592 return err
593 }
594 omciRxCallbackPair := CallbackPair{tid, oo.receiveMibSyncResponse}
595 return oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
596}
597
598func (oo *OmciCC) sendMibUpload(ctx context.Context, timeout int, highPrio bool) error {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000599 logger.Debugw("send MibUpload-msg to:", log.Fields{"deviceId": oo.deviceID})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000600 request := &omci.MibUploadRequest{
601 MeBasePacket: omci.MeBasePacket{
602 EntityClass: me.OnuDataClassID,
603 },
604 }
605 tid := oo.GetNextTid(highPrio)
606 pkt, err := serialize(omci.MibUploadRequestType, request, tid)
607 if err != nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000608 logger.Errorw("Cannot serialize MibUploadRequest", log.Fields{"Err": err})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000609 return err
610 }
611 oo.uploadSequNo = 0
612 oo.uploadNoOfCmds = 0
613
614 omciRxCallbackPair := CallbackPair{tid, oo.receiveMibSyncResponse}
615 return oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
616}
617
618func (oo *OmciCC) sendMibUploadNext(ctx context.Context, timeout int, highPrio bool) error {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000619 logger.Debugw("send MibUploadNext-msg to:", log.Fields{"deviceId": oo.deviceID, "uploadSequNo": oo.uploadSequNo})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000620 request := &omci.MibUploadNextRequest{
621 MeBasePacket: omci.MeBasePacket{
622 EntityClass: me.OnuDataClassID,
623 },
624 CommandSequenceNumber: oo.uploadSequNo,
625 }
626 tid := oo.GetNextTid(highPrio)
627 pkt, err := serialize(omci.MibUploadNextRequestType, request, tid)
628 if err != nil {
Holger Hildebrandt0f9b88d2020-04-20 13:33:25 +0000629 logger.Errorw("Cannot serialize MibUploadNextRequest", log.Fields{"Err": err})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000630 return err
631 }
632 oo.uploadSequNo++
633
634 omciRxCallbackPair := CallbackPair{tid, oo.receiveMibSyncResponse}
635 return oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
636}
637
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +0000638func (oo *OmciCC) sendCreateGalEthernetProfile(ctx context.Context, timeout int, highPrio bool) *me.ManagedEntity {
639 tid := oo.GetNextTid(highPrio)
640 logger.Debugw("send GalEnetProfile-Create-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
Holger Hildebrandtfa074992020-03-27 15:42:06 +0000641
Holger Hildebrandtdd23cc22020-05-19 13:32:18 +0000642 meParams := me.ParamData{
643 EntityID: galEthernetEID,
644 Attributes: me.AttributeValueMap{"MaximumGemPayloadSize": maxGemPayloadSize},
645 }
646 meInstance, omciErr := me.NewGalEthernetProfile(meParams)
647 if omciErr.GetError() == nil {
648 //all setByCreate parameters already set, no default option required ...
649 omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType, omci.TransactionID(tid))
650 if err != nil {
651 logger.Errorw("Cannot encode GalEnetProfileInstance for create", log.Fields{"Err": err})
652 return nil
653 }
654
655 pkt, err := serializeOmciLayer(omciLayer, msgLayer)
656 if err != nil {
657 logger.Errorw("Cannot serialize GalEnetProfile create", log.Fields{"Err": err})
658 return nil
659 }
660
661 omciRxCallbackPair := CallbackPair{tid, oo.ReceiveMibDownloadResponse}
662 err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
663 if err != nil {
664 logger.Errorw("Cannot send GalEnetProfile create", log.Fields{"Err": err})
665 return nil
666 } else {
667 logger.Debug("send GalEnetProfile-Create-msg done")
668 return meInstance
669 }
670 } else {
671 logger.Errorw("Cannot generate GalEnetProfileInstance", log.Fields{"Err": omciErr.GetError()})
672 return nil
673 }
674}
675
676// might be needed to extend for parameter arguments, here just for setting the VonnectivityMode!!
677func (oo *OmciCC) sendSetOnu2g(ctx context.Context, timeout int, highPrio bool) *me.ManagedEntity {
678 tid := oo.GetNextTid(highPrio)
679 logger.Debugw("send ONU2-G-Set-msg:", log.Fields{"deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16)})
680
681 // here we should better use the MibUpload stored ONU2-G data to re-use the given InstanceNumber
682 // and to verify, if the ONU really supports the desired connectivity mode 5 (in ConnCap)
683 // By now we just use fix values to fire - this is anyway what the python adapter does
684 // read ONU-2G from DB ???? //TODO!!!
685 meParams := me.ParamData{
686 EntityID: 0,
687 Attributes: me.AttributeValueMap{"CurrentConnectivityMode": connectivityModeValue},
688 }
689 meInstance, omciErr := me.NewOnu2G(meParams)
690 if omciErr.GetError() == nil {
691 omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.SetRequestType, omci.TransactionID(tid))
692 if err != nil {
693 logger.Errorw("Cannot encode ONU2-G instance for set", log.Fields{"Err": err})
694 return nil
695 }
696
697 pkt, err := serializeOmciLayer(omciLayer, msgLayer)
698 if err != nil {
699 logger.Errorw("Cannot serialize ONU2-G set", log.Fields{"Err": err})
700 return nil
701 }
702
703 omciRxCallbackPair := CallbackPair{tid, oo.ReceiveMibDownloadResponse}
704 err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
705 if err != nil {
706 logger.Errorw("Cannot send ONU2-G set", log.Fields{"Err": err})
707 return nil
708 } else {
709 logger.Debug("send ONU2-G-Set-msg done")
710 return meInstance
711 }
712 } else {
713 logger.Errorw("Cannot generate ONU2-G", log.Fields{"Err": omciErr.GetError()})
714 return nil
715 }
716}
717
718func (oo *OmciCC) sendCreateMBServiceProfile(ctx context.Context,
719 a_pUniPort *OnuUniPort, timeout int, highPrio bool) *me.ManagedEntity {
720 tid := oo.GetNextTid(highPrio)
721 instID := macBridgeServiceProfileEID + uint16(a_pUniPort.macBpNo)
722 logger.Debugw("send MBSP-Create-msg:", log.Fields{
723 "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": instID})
724
725 meParams := me.ParamData{
726 EntityID: instID,
727 Attributes: me.AttributeValueMap{
728 "Priority": 0x8000,
729 "MaxAge": 20 * 256, //20s
730 "HelloTime": 2 * 256, //2s
731 "ForwardDelay": 15 * 256, //15s
732 //note: DynamicFilteringAgeingTime is taken from omci lib default as
733 // which is obviously different from default value used in python lib,
734 // where the value seems to be 0 (ONU defined) - to be considered in case of test artifacts ...
735 },
736 }
737
738 meInstance, omciErr := me.NewMacBridgeServiceProfile(meParams)
739 if omciErr.GetError() == nil {
740 //obviously we have to set all 'untouched' parameters to default by some additional option parameter!!
741 omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
742 omci.TransactionID(tid), omci.AddDefaults(true))
743 if err != nil {
744 logger.Errorw("Cannot encode MBSP for create", log.Fields{"Err": err})
745 return nil
746 }
747
748 pkt, err := serializeOmciLayer(omciLayer, msgLayer)
749 if err != nil {
750 logger.Errorw("Cannot serialize MBSP create", log.Fields{"Err": err})
751 return nil
752 }
753
754 omciRxCallbackPair := CallbackPair{tid, oo.ReceiveMibDownloadResponse}
755 err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
756 if err != nil {
757 logger.Errorw("Cannot send MBSP create", log.Fields{"Err": err})
758 return nil
759 } else {
760 logger.Debug("send MBSP-Create-msg done")
761 return meInstance
762 }
763 } else {
764 logger.Errorw("Cannot generate MBSP Instance", log.Fields{"Err": omciErr.GetError()})
765 return nil
766 }
767}
768
769func (oo *OmciCC) sendCreateMBPConfigData(ctx context.Context,
770 a_pUniPort *OnuUniPort, timeout int, highPrio bool) *me.ManagedEntity {
771 tid := oo.GetNextTid(highPrio)
772 instID := macBridgePortAniEID + a_pUniPort.entityId
773 logger.Debugw("send MBPCD-Create-msg:", log.Fields{
774 "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": instID})
775
776 meParams := me.ParamData{
777 EntityID: instID,
778 Attributes: me.AttributeValueMap{
779 "BridgeIdPointer": macBridgeServiceProfileEID + uint16(a_pUniPort.macBpNo),
780 "PortNum": a_pUniPort.macBpNo,
781 "TpType": uint8(a_pUniPort.portType),
782 "TpPointer": a_pUniPort.entityId,
783 },
784 }
785 meInstance, omciErr := me.NewMacBridgePortConfigurationData(meParams)
786 if omciErr.GetError() == nil {
787 //obviously we have to set all 'untouched' parameters to default by some additional option parameter!!
788 omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType,
789 omci.TransactionID(tid), omci.AddDefaults(true))
790 if err != nil {
791 logger.Errorw("Cannot encode MBPCD for create", log.Fields{"Err": err})
792 return nil
793 }
794
795 pkt, err := serializeOmciLayer(omciLayer, msgLayer)
796 if err != nil {
797 logger.Errorw("Cannot serialize MBPCD create", log.Fields{"Err": err})
798 return nil
799 }
800
801 omciRxCallbackPair := CallbackPair{tid, oo.ReceiveMibDownloadResponse}
802 err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
803 if err != nil {
804 logger.Errorw("Cannot send MBPCD create", log.Fields{"Err": err})
805 return nil
806 } else {
807 logger.Debug("send MBPCD-Create-msg done")
808 return meInstance
809 }
810 } else {
811 logger.Errorw("Cannot generate MBPCD Instance", log.Fields{"Err": omciErr.GetError()})
812 return nil
813 }
814}
815
816func (oo *OmciCC) sendCreateEVTOConfigData(ctx context.Context,
817 a_pUniPort *OnuUniPort, timeout int, highPrio bool) *me.ManagedEntity {
818 tid := oo.GetNextTid(highPrio)
819 //same entityId is used as for MBSP (see there), but just arbitrary ...
820 instID := macBridgeServiceProfileEID + uint16(a_pUniPort.macBpNo)
821 logger.Debugw("send EVTOCD-Create-msg:", log.Fields{
822 "deviceId": oo.deviceID, "SequNo": strconv.FormatInt(int64(tid), 16), "InstId": instID})
823
824 // compare python adapter code WA VOL-1311: this is not done here!
825 // (setting TPID values for the create would probably anyway be ignored by the omci lib)
826 // but perhaps we have to be aware of possible problems at get(Next) Request handling for EVTOOCD tables later ...
827 assType := uint8(2) // default AssociationType is PPTPEthUni
828 if a_pUniPort.portType == UniVEIP {
829 assType = uint8(10) // for VEIP
830 }
831 meParams := me.ParamData{
832 EntityID: instID,
833 Attributes: me.AttributeValueMap{
834 "AssociationType": assType,
835 "AssociatedMePointer": a_pUniPort.entityId,
836 },
837 }
838 meInstance, omciErr := me.NewExtendedVlanTaggingOperationConfigurationData(meParams)
839 if omciErr.GetError() == nil {
840 //all setByCreate parameters already set, no default option required ...
841 omciLayer, msgLayer, err := omci.EncodeFrame(meInstance, omci.CreateRequestType, omci.TransactionID(tid))
842 if err != nil {
843 logger.Errorw("Cannot encode EVTOCD for create", log.Fields{"Err": err})
844 return nil
845 }
846
847 pkt, err := serializeOmciLayer(omciLayer, msgLayer)
848 if err != nil {
849 logger.Errorw("Cannot serialize EVTOCD create", log.Fields{"Err": err})
850 return nil
851 }
852
853 omciRxCallbackPair := CallbackPair{tid, oo.ReceiveMibDownloadResponse}
854 err = oo.Send(ctx, pkt, timeout, 0, highPrio, omciRxCallbackPair)
855 if err != nil {
856 logger.Errorw("Cannot send EVTOCD create", log.Fields{"Err": err})
857 return nil
858 } else {
859 logger.Debug("send EVTOCD-Create-msg done")
860 return meInstance
861 }
862 } else {
863 logger.Errorw("Cannot generate EVTOCD Instance", log.Fields{"Err": omciErr.GetError()})
864 return nil
865 }
866}