| /* |
| * Copyright 2019-present Open Networking Foundation |
| |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package adaptercore |
| |
| import ( |
| "errors" |
| "fmt" |
| |
| "github.com/opencord/voltha-go/common/log" |
| openolt "github.com/opencord/voltha-protos/go/openolt" |
| "github.com/opencord/voltha-protos/go/voltha" |
| ) |
| |
| type PonPort struct { |
| /* |
| This is a highly reduced version taken from the adtran pon_port. |
| TODO: Extend for use in the openolt adapter set. |
| */ |
| /* MAX_ONUS_SUPPORTED = 256 |
| DEFAULT_ENABLED = False |
| MAX_DEPLOYMENT_RANGE = 25000 # Meters (OLT-PB maximum) |
| |
| _MCAST_ONU_ID = 253 |
| _MCAST_ALLOC_BASE = 0x500 |
| |
| _SUPPORTED_ACTIVATION_METHODS = ['autodiscovery'] # , 'autoactivate'] |
| _SUPPORTED_AUTHENTICATION_METHODS = ['serial-number'] |
| */ |
| PONID uint32 |
| DeviceID string |
| IntfID uint32 |
| PortNum uint32 |
| PortID uint32 |
| Label string |
| ONUs map[uint32]interface{} |
| ONUsByID map[uint32]interface{} |
| |
| RxBytes uint64 |
| RxPackets uint64 |
| RxMcastPackets uint64 |
| RxBcastPackets uint64 |
| RxErrorPackets uint64 |
| TxBytes uint64 |
| TxPackets uint64 |
| TxUcastPackets uint64 |
| TxMcastPackets uint64 |
| TxBcastPackets uint64 |
| TxErrorPackets uint64 |
| } |
| |
| func NewPONPort(PONID uint32, DeviceID string, IntfID uint32, PortNum uint32) *PonPort { |
| |
| var PON PonPort |
| |
| PON.PONID = PONID |
| PON.DeviceID = DeviceID |
| PON.IntfID = IntfID |
| PON.PortNum = PortNum |
| PON.PortID = 0 |
| PON.Label = fmt.Sprintf("%s,%d", "pon-", PONID) |
| |
| PON.ONUs = make(map[uint32]interface{}) |
| PON.ONUsByID = make(map[uint32]interface{}) |
| |
| /* |
| Statistics taken from nni_port |
| self.intf_id = 0 #handled by getter |
| self.port_no = 0 #handled by getter |
| self.port_id = 0 #handled by getter |
| |
| Note: In the current implementation of the kpis coming from the BAL the stats are the |
| samne model for NNI and PON. |
| |
| TODO: Integrate additional kpis for the PON and other southbound port objecgts. |
| |
| */ |
| |
| PON.RxBytes = 0 |
| PON.RxPackets = 0 |
| PON.RxMcastPackets = 0 |
| PON.RxBcastPackets = 0 |
| PON.RxErrorPackets = 0 |
| PON.TxBytes = 0 |
| PON.TxPackets = 0 |
| PON.TxUcastPackets = 0 |
| PON.TxMcastPackets = 0 |
| PON.TxBcastPackets = 0 |
| PON.TxErrorPackets = 0 |
| |
| /* def __str__(self): |
| return "PonPort-{}: Admin: {}, Oper: {}, OLT: {}".format(self._label, |
| self._admin_state, |
| self._oper_status, |
| self.olt) |
| */ |
| return &PON |
| } |
| |
| type NniPort struct { |
| /* |
| Northbound network port, often Ethernet-based |
| |
| This is a highly reduced version taken from the adtran nni_port code set |
| TODO: add functions to allow for port specific values and operations |
| */ |
| PortNum uint32 |
| Name string |
| LogicalPort uint32 |
| IntfID uint32 |
| |
| RxBytes uint64 |
| RxPackets uint64 |
| RxMcastPackets uint64 |
| RxBcastPackets uint64 |
| RxErrorPackets uint64 |
| TxBytes uint64 |
| TxPackets uint64 |
| TxUcastPackets uint64 |
| TxMcastPackets uint64 |
| TxBcastPackets uint64 |
| TxErrorPackets uint64 |
| } |
| |
| func NewNniPort(PortNum uint32, IntfID uint32) *NniPort { |
| |
| var NNI NniPort |
| |
| NNI.PortNum = PortNum |
| NNI.Name = fmt.Sprintf("%s,%d", "nni-", PortNum) |
| NNI.IntfID = IntfID |
| |
| NNI.RxBytes = 0 |
| NNI.RxPackets = 0 |
| NNI.RxMcastPackets = 0 |
| NNI.RxBcastPackets = 0 |
| NNI.RxErrorPackets = 0 |
| NNI.TxBytes = 0 |
| NNI.TxPackets = 0 |
| NNI.TxUcastPackets = 0 |
| NNI.TxMcastPackets = 0 |
| NNI.TxBcastPackets = 0 |
| NNI.TxErrorPackets = 0 |
| |
| return &NNI |
| } |
| |
| type OpenOltStatisticsMgr struct { |
| Device *DeviceHandler |
| NorthBoundPort map[uint32]NniPort |
| SouthBoundPort map[uint32]PonPort |
| // TODO PMMetrics Metrics |
| } |
| |
| func NewOpenOltStatsMgr(Dev *DeviceHandler) *OpenOltStatisticsMgr { |
| |
| var StatMgr OpenOltStatisticsMgr |
| |
| StatMgr.Device = Dev |
| // TODO call metric PMMetric = |
| // Northbound and Southbound ports |
| // added to initialize the pm_metrics |
| var Ports interface{} |
| Ports, _ = InitPorts("nni", Dev.deviceId) |
| StatMgr.NorthBoundPort, _ = Ports.(map[uint32]NniPort) |
| Ports, _ = InitPorts("pon", Dev.deviceId) |
| StatMgr.SouthBoundPort, _ = Ports.(map[uint32]PonPort) |
| |
| return &StatMgr |
| } |
| |
| func InitPorts(Intftype string, DeviceID string) (interface{}, error) { |
| /* |
| This method collects the port objects: nni and pon that are updated with the |
| current data from the OLT |
| |
| Both the northbound (nni) and southbound ports are indexed by the interface id (intf_id) |
| and NOT the port number. When the port object is instantiated it will contain the intf_id and |
| port_no values |
| |
| :param type: |
| :return: |
| */ |
| var i uint32 |
| if Intftype == "nni" { |
| NniPorts := make(map[uint32]NniPort) |
| for i = 0; i <= 1; i++ { |
| Port := BuildPortObject(i, "nni", DeviceID).(NniPort) |
| NniPorts[Port.IntfID] = Port |
| } |
| return NniPorts, nil |
| } else if Intftype == "pon" { |
| PONPorts := make(map[uint32]PonPort) |
| for i = 0; i <= 16; i++ { |
| PONPort := BuildPortObject(i, "pon", DeviceID).(PonPort) |
| PONPorts[PONPort.IntfID] = PONPort |
| } |
| return PONPorts, nil |
| } else { |
| log.Errorf("Invalid type of interface %s", Intftype) |
| return nil, errors.New("Invalid type of interface ") |
| } |
| } |
| |
| func BuildPortObject(PortNum uint32, IntfType string, DeviceID string) interface{} { |
| /* |
| Seperate method to allow for updating north and southbound ports |
| newly discovered ports and devices |
| |
| :param port_num: |
| :param type: |
| :return: |
| */ |
| |
| //This builds a port object which is added to the |
| //appropriate northbound or southbound values |
| if IntfType == "nni" { |
| IntfID := IntfIdToPortNo(PortNum, voltha.Port_ETHERNET_UNI) |
| return NewNniPort(PortNum, IntfID) |
| } else if IntfType == "pon" { |
| // PON ports require a different configuration |
| // intf_id and pon_id are currently equal. |
| IntfID := IntfIdToPortNo(PortNum, voltha.Port_ETHERNET_NNI) |
| PONID := IntfID |
| return NewPONPort(PONID, DeviceID, IntfID, PortNum) |
| } else { |
| log.Errorf("Invalid type of interface %s", IntfType) |
| return nil |
| } |
| } |
| |
| func (StatMgr *OpenOltStatisticsMgr) PortStatisticsIndication(PortStats *openolt.PortStatistics) { |
| log.Debugf("port-stats-collected %v", PortStats) |
| StatMgr.PortsStatisticsKpis(PortStats) |
| // TODO send stats to core topic to the voltha kafka or a different kafka ? |
| } |
| |
| func FlowStatisticsIndication(self, FlowStats *openolt.FlowStatistics) { |
| log.Debugf("flow-stats-collected %v", FlowStats) |
| //TODO send to kafka ? |
| } |
| |
| func (StatMgr *OpenOltStatisticsMgr) PortsStatisticsKpis(PortStats *openolt.PortStatistics) { |
| |
| /*map the port stats values into a dictionary |
| Create a kpoEvent and publish to Kafka |
| |
| :param port_stats: |
| :return: |
| */ |
| //var err error |
| IntfID := PortStats.IntfId |
| |
| if (IntfIdToPortNo(0, voltha.Port_ETHERNET_NNI) < IntfID) && |
| (IntfID < IntfIdToPortNo(4, voltha.Port_ETHERNET_NNI)) { |
| /* |
| for this release we are only interested in the first NNI for |
| Northbound. |
| we are not using the other 3 |
| */ |
| return |
| } else { |
| |
| PMData := make(map[string]uint64) |
| PMData["rx_bytes"] = PortStats.RxBytes |
| PMData["rx_packets"] = PortStats.RxPackets |
| PMData["rx_ucast_packets"] = PortStats.RxUcastPackets |
| PMData["rx_mcast_packets"] = PortStats.RxMcastPackets |
| PMData["rx_bcast_packets"] = PortStats.RxBcastPackets |
| PMData["rx_error_packets"] = PortStats.RxErrorPackets |
| PMData["tx_bytes"] = PortStats.TxBytes |
| PMData["tx_packets"] = PortStats.TxPackets |
| PMData["tx_ucast_packets"] = PortStats.TxUcastPackets |
| PMData["tx_mcast_packets"] = PortStats.TxMcastPackets |
| PMData["tx_bcast_packets"] = PortStats.TxBcastPackets |
| PMData["tx_error_packets"] = PortStats.TxErrorPackets |
| PMData["rx_crc_errors"] = PortStats.RxCrcErrors |
| PMData["bip_errors"] = PortStats.BipErrors |
| |
| PMData["intf_id"] = uint64(PortStats.IntfId) |
| |
| /* |
| Based upon the intf_id map to an nni port or a pon port |
| the intf_id is the key to the north or south bound collections |
| |
| Based upon the intf_id the port object (nni_port or pon_port) will |
| have its data attr. updated by the current dataset collected. |
| |
| For prefixing the rule is currently to use the port number and not the intf_id |
| */ |
| //FIXME : Just use first NNI for now |
| /* TODO should the data be marshalled before sending it ? |
| if IntfID == IntfIdToPortNo(0, voltha.Port_ETHERNET_NNI) { |
| //NNI port (just the first one) |
| err = UpdatePortObjectKpiData(StatMgr.NorthBoundPorts[PortStats.IntfID], PMData) |
| } else { |
| //PON ports |
| err = UpdatePortObjectKpiData(SouthboundPorts[PortStats.IntfID], PMData) |
| } |
| if (err != nil) { |
| log.Error("Error publishing statistics data") |
| } |
| */ |
| } |
| } |