Zdravko Bozakov | 7401ff2 | 2019-05-28 22:45:12 +0200 | [diff] [blame] | 1 | /* |
| 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 | package core |
| 18 | |
| 19 | import ( |
| 20 | "strconv" |
| 21 | |
Zack Williams | 2abf393 | 2019-08-05 14:07:05 -0700 | [diff] [blame] | 22 | pb "github.com/opencord/voltha-bbsim/api" |
| 23 | "github.com/opencord/voltha-bbsim/common/logger" |
| 24 | "github.com/opencord/voltha-bbsim/device" |
Matt Jeanneret | 7c9c5f2 | 2019-08-09 14:40:12 -0400 | [diff] [blame] | 25 | openolt "github.com/opencord/voltha-protos/go/openolt" |
Zdravko Bozakov | 7401ff2 | 2019-05-28 22:45:12 +0200 | [diff] [blame] | 26 | "google.golang.org/grpc/codes" |
| 27 | "google.golang.org/grpc/status" |
| 28 | ) |
| 29 | |
| 30 | const ( |
| 31 | // OnuLossOfPloam is state on onu los |
| 32 | OnuLossOfPloam = "lossofploam" |
| 33 | // OnuLossOfOmciChannel is the state on omci channel loss alarm |
| 34 | OnuLossOfOmciChannel = "lossofomcichannel" |
| 35 | // OnuSignalDegrade is the state on signal degrade alarm |
| 36 | OnuSignalDegrade = "signaldegrade" |
| 37 | // AlarmOn is for raising the alarm |
| 38 | AlarmOn = "on" |
| 39 | // AlarmOff is for clearing the alarm |
| 40 | AlarmOff = "off" |
| 41 | ) |
| 42 | |
| 43 | func (s *Server) handleOnuAlarm(in *pb.ONUAlarmRequest) (*pb.BBSimResponse, error) { |
| 44 | value, ok := s.SNmap.Load(in.OnuSerial) |
| 45 | onu := value.(*device.Onu) |
| 46 | if !ok { |
| 47 | return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, "no active or discovered onu found with serial number "+in.OnuSerial) |
| 48 | } |
| 49 | |
| 50 | if (onu.InternalState == device.ONU_LOS_RAISED || onu.InternalState == device.ONU_LOS_ON_OLT_PON_LOS) && |
| 51 | (in.AlarmType != OnuLossOfPloam) { |
| 52 | return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, in.OnuSerial+" is not reachable, can not send onu alarm") |
| 53 | } |
| 54 | |
| 55 | if s.Olt.PonIntfs[onu.IntfID].AlarmState == device.PonLosRaised && (in.AlarmType != OnuLossOfPloam) { |
| 56 | // Don't send onu alarm as OLT-PON is down |
| 57 | return &pb.BBSimResponse{}, status.Errorf(codes.Aborted, "pon-port down, can not send onu alarm") |
| 58 | } |
| 59 | switch in.AlarmType { |
| 60 | case OnuLossOfOmciChannel: |
| 61 | Ind := formulateLossOfOmciChannelAlarm(in.Status, onu) |
| 62 | if in.Status == AlarmOn { |
| 63 | onu.UpdateIntState(device.ONU_OMCI_CHANNEL_LOS_RAISED) |
| 64 | } else { |
| 65 | onu.UpdateIntState(device.ONU_ACTIVE) |
| 66 | } |
| 67 | s.alarmCh <- Ind |
| 68 | return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil |
| 69 | |
| 70 | case OnuSignalDegrade: |
| 71 | Ind := formulateSignalDegradeAlarm(in.Status, onu) |
| 72 | s.alarmCh <- Ind |
| 73 | return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil |
| 74 | |
| 75 | case OnuLossOfPloam: |
| 76 | if in.Status == AlarmOn { |
| 77 | onu.UpdateIntState(device.ONU_LOS_RAISED) |
| 78 | device.UpdateOnusOpStatus(onu.IntfID, onu, "down") |
| 79 | } else { |
| 80 | onu.UpdateIntState(device.ONU_ACTIVE) |
| 81 | device.UpdateOnusOpStatus(onu.IntfID, onu, "up") |
| 82 | // TODO is it required to check onu state? |
| 83 | err := sendOnuDiscInd(*s.EnableServer, onu) |
| 84 | if err != nil { |
| 85 | logger.Error("Error: %v", err.Error()) |
| 86 | } |
| 87 | } |
| 88 | Ind := formulateLossOfPLOAM(in.Status, onu) |
| 89 | s.alarmCh <- Ind |
Mahir Gunyel | 32dfd72 | 2019-08-05 16:18:06 +0300 | [diff] [blame] | 90 | er := sendOnuInd(*s.EnableServer, onu, onu.OperState, "up") |
Zdravko Bozakov | 7401ff2 | 2019-05-28 22:45:12 +0200 | [diff] [blame] | 91 | if er != nil { |
| 92 | logger.Debug(er.Error()) |
| 93 | } |
| 94 | |
| 95 | resp, err := s.checkAndSendOltPonLos(in.OnuSerial, in.Status, device.IntfPon) // Send olt los if all the onus attached to a pon-port shows los |
| 96 | if err != nil { |
| 97 | return resp, err |
| 98 | } |
| 99 | return resp, nil |
| 100 | |
| 101 | default: |
| 102 | logger.Debug("Unhandled alarm type") |
| 103 | return &pb.BBSimResponse{}, status.Errorf(codes.Unimplemented, "Unhandled alarm type") |
| 104 | } |
| 105 | |
| 106 | } |
| 107 | |
| 108 | func (s *Server) handleOltAlarm(in *pb.OLTAlarmRequest) (*pb.BBSimResponse, error) { |
| 109 | switch in.PortType { |
| 110 | case device.IntfNni: |
| 111 | |
| 112 | if !s.isNniIntfPresentInOlt(in.PortId) { |
| 113 | return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, strconv.Itoa(int(in.PortId))+" NNI not present in olt") |
| 114 | } |
| 115 | |
| 116 | Ind := formulateOLTLOSAlarm(in.Status, in.PortId, device.IntfNni) |
| 117 | s.alarmCh <- Ind |
| 118 | s.setNNIPortState(in.PortId, in.Status) |
| 119 | |
| 120 | case device.IntfPon: |
| 121 | if !s.isPonIntfPresentInOlt(in.PortId) { |
| 122 | return &pb.BBSimResponse{}, status.Errorf(codes.NotFound, strconv.Itoa(int(in.PortId))+" PON not present in olt") |
| 123 | } |
| 124 | Ind := formulateOLTLOSAlarm(in.Status, in.PortId, in.PortType) |
| 125 | s.alarmCh <- Ind |
| 126 | onusOperstat := s.setPONPortState(in.PortId, in.Status) |
| 127 | for _, onu := range s.Onumap[in.PortId] { |
| 128 | if onu.InternalState == device.ONU_LOS_RAISED || onu.InternalState == device.ONU_FREE { |
| 129 | continue // Skip for onus which have independently raised onu los |
| 130 | } |
| 131 | |
Mahir Gunyel | 32dfd72 | 2019-08-05 16:18:06 +0300 | [diff] [blame] | 132 | er := sendOnuInd(*s.EnableServer, onu, onusOperstat, "up") |
Zdravko Bozakov | 7401ff2 | 2019-05-28 22:45:12 +0200 | [diff] [blame] | 133 | if er != nil { |
| 134 | logger.Debug(er.Error()) |
| 135 | } |
| 136 | s.sendOnuLosOnOltPonLos(onu, in.Status) |
| 137 | } |
| 138 | default: |
| 139 | return &pb.BBSimResponse{}, status.Errorf(codes.Internal, "invalid interface type provided") |
| 140 | } |
| 141 | |
| 142 | return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil |
| 143 | } |
| 144 | |
| 145 | func (s *Server) setNNIPortState(portID uint32, alarmstatus string) { |
| 146 | switch alarmstatus { |
| 147 | case AlarmOn: |
| 148 | s.Olt.UpdateNniPortState(portID, device.NniLosRaised, "down") |
| 149 | |
| 150 | case AlarmOff: |
| 151 | s.Olt.UpdateNniPortState(portID, device.NniLosCleared, "up") |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | func (s *Server) setPONPortState(portID uint32, alarmstatus string) string { |
| 156 | switch alarmstatus { |
| 157 | case AlarmOn: |
| 158 | s.Olt.UpdatePonPortState(portID, device.PonLosRaised, "down") |
| 159 | return "down" |
| 160 | |
| 161 | case AlarmOff: |
| 162 | s.Olt.UpdatePonPortState(portID, device.PonLosCleared, "up") |
| 163 | return "up" |
| 164 | } |
| 165 | return "" |
| 166 | } |
| 167 | |
| 168 | func (s *Server) sendOnuLosOnOltPonLos(onu *device.Onu, status string) { |
| 169 | var internalState device.DeviceState |
| 170 | |
| 171 | if status == AlarmOn { |
| 172 | internalState = device.ONU_LOS_ON_OLT_PON_LOS |
| 173 | } else if status == AlarmOff { |
| 174 | internalState = device.ONU_ACTIVE |
| 175 | } |
| 176 | |
| 177 | Ind := formulateLossOfPLOAM(status, onu) |
| 178 | onu.UpdateIntState(internalState) |
| 179 | |
| 180 | // update onus slice on alarm off |
| 181 | if status == "off" { |
| 182 | err := sendOnuDiscInd(*s.EnableServer, onu) |
| 183 | if err != nil { |
| 184 | logger.Error(err.Error()) |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | s.alarmCh <- Ind |
| 189 | } |
| 190 | |
| 191 | func formulateLossOfOmciChannelAlarm(status string, onu *device.Onu) *openolt.Indication { |
| 192 | logger.Debug("formulateLossofOmciChannelAlarm() invoked") |
| 193 | |
| 194 | alarmIndication := &openolt.AlarmIndication_OnuLossOmciInd{ |
| 195 | OnuLossOmciInd: &openolt.OnuLossOfOmciChannelIndication{ |
| 196 | IntfId: onu.IntfID, |
| 197 | OnuId: onu.OnuID, |
| 198 | Status: status, |
| 199 | }, |
| 200 | } |
| 201 | |
| 202 | alarmind := &openolt.AlarmIndication{ |
| 203 | Data: alarmIndication, |
| 204 | } |
| 205 | |
| 206 | msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind} |
| 207 | Ind := &openolt.Indication{Data: msg} |
| 208 | return Ind |
| 209 | } |
| 210 | |
| 211 | func formulateSignalDegradeAlarm(status string, onu *device.Onu) *openolt.Indication { |
| 212 | logger.Debug("formulateSignalDegrade() invoked") |
| 213 | alarmIndication := &openolt.AlarmIndication_OnuSignalDegradeInd{ |
| 214 | OnuSignalDegradeInd: &openolt.OnuSignalDegradeIndication{ |
| 215 | IntfId: onu.IntfID, |
| 216 | OnuId: onu.OnuID, |
| 217 | Status: status, |
| 218 | InverseBitErrorRate: 0, |
| 219 | }, |
| 220 | } |
| 221 | alarmind := &openolt.AlarmIndication{ |
| 222 | Data: alarmIndication, |
| 223 | } |
| 224 | msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind} |
| 225 | Ind := &openolt.Indication{Data: msg} |
| 226 | return Ind |
| 227 | } |
| 228 | |
| 229 | func formulateLossOfPLOAM(status string, onu *device.Onu) *openolt.Indication { |
| 230 | logger.Debug("formulateLossOfPLOAM() invoked") |
| 231 | |
| 232 | alarmIndication := &openolt.AlarmIndication_OnuAlarmInd{OnuAlarmInd: &openolt.OnuAlarmIndication{ |
| 233 | IntfId: onu.IntfID, |
| 234 | OnuId: onu.OnuID, |
| 235 | LosStatus: status, |
| 236 | LobStatus: status, |
| 237 | LopcMissStatus: status, |
| 238 | LopcMicErrorStatus: status, |
| 239 | }} |
| 240 | |
| 241 | alarmind := &openolt.AlarmIndication{Data: alarmIndication} |
| 242 | msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind} |
| 243 | Ind := &openolt.Indication{Data: msg} |
| 244 | return Ind |
| 245 | } |
| 246 | |
| 247 | func formulateOLTLOSAlarm(status string, PortID uint32, intfType string) *openolt.Indication { |
| 248 | intfID := interfaceIDToPortNo(PortID, intfType) |
| 249 | |
| 250 | alarmIndication := &openolt.AlarmIndication_LosInd{LosInd: &openolt.LosIndication{ |
| 251 | IntfId: intfID, |
| 252 | Status: status, |
| 253 | }} |
| 254 | |
| 255 | alarmind := &openolt.AlarmIndication{Data: alarmIndication} |
| 256 | msg := &openolt.Indication_AlarmInd{AlarmInd: alarmind} |
| 257 | Ind := &openolt.Indication{Data: msg} |
| 258 | return Ind |
| 259 | } |
| 260 | |
| 261 | func (s *Server) checkAndSendOltPonLos(serial string, status string, intfType string) (*pb.BBSimResponse, error) { |
| 262 | value, _ := s.SNmap.Load(serial) |
| 263 | onu := value.(*device.Onu) |
| 264 | if s.getNoOfActiveOnuByPortID(onu.IntfID) == 0 { |
| 265 | logger.Warn("Warning: Sending OLT-LOS, as all onus on pon-port %v raised los", onu.IntfID) |
| 266 | request := &pb.OLTAlarmRequest{PortId: onu.IntfID, Status: AlarmOn, PortType: device.IntfPon} |
| 267 | resp, err := s.handleOltAlarm(request) |
| 268 | return resp, err |
| 269 | } |
| 270 | if s.Olt.PonIntfs[onu.IntfID].AlarmState == device.PonLosRaised && status == AlarmOff { |
| 271 | s.setPONPortState(onu.IntfID, status) |
| 272 | Ind := formulateOLTLOSAlarm(status, onu.IntfID, intfType) |
| 273 | s.alarmCh <- Ind |
| 274 | } |
| 275 | |
| 276 | return &pb.BBSimResponse{StatusMsg: RequestAccepted}, nil |
| 277 | } |
| 278 | |
| 279 | func interfaceIDToPortNo(intfid uint32, intfType string) uint32 { |
| 280 | // Converts interface-id to port-numbers that can be understood by the voltha |
| 281 | if intfType == device.IntfNni { |
| 282 | // nni at voltha starts with 65536 |
| 283 | // nni = 65536 + interface_id |
| 284 | return 0x1<<16 + intfid |
| 285 | } else if intfType == device.IntfPon { |
| 286 | // pon = 536,870,912 + interface_id |
| 287 | return (0x2 << 28) + intfid // In openolt code, stats_collection.cc line number 196, pon starts from 0 |
| 288 | // In bbsim, pon starts from 1 |
| 289 | } |
| 290 | return 0 |
| 291 | } |