Updated Adapter to support to handle DHCP trap on NNI and packet-in/out and Bug Fixing.
Tested EAPOL/DHCP/HSIA functionality E2E with EdgeCore OLT and TWSH ONU KIT.
patch: PON port is derived from platform and sent to core and bug fixes
Retested EAPOL/DHCP/HSIA use case end to end with EdgeCore OLT and TWSH ONU KIT
Change-Id: I99df82fd7a1385c10878f6fe09ce0d30c48d8e99
diff --git a/adaptercore/device_handler.go b/adaptercore/device_handler.go
index 3bb34db..866f815 100644
--- a/adaptercore/device_handler.go
+++ b/adaptercore/device_handler.go
@@ -27,6 +27,7 @@
"github.com/gogo/protobuf/proto"
"github.com/golang/protobuf/ptypes"
+ "github.com/mdlayher/ethernet"
com "github.com/opencord/voltha-go/adapters/common"
"github.com/opencord/voltha-go/common/log"
rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
@@ -128,12 +129,7 @@
} else {
operStatus = voltha.OperStatus_DISCOVERED
}
- // portNum := IntfIdToPortNo(intfId,portType)
- portNum := intfId
- if portType == voltha.Port_ETHERNET_NNI {
- portNum = IntfIdToPortNo(intfId, portType)
- }
- // portNum := IntfIdToPortNo(intfId,portType)
+ portNum := IntfIdToPortNo(intfId, portType)
label := GetportLabel(portNum, portType)
if len(label) == 0 {
log.Errorw("Invalid-port-label", log.Fields{"portNum": portNum, "portType": portType})
@@ -251,6 +247,7 @@
case *oop.Indication_PktInd:
pktInd := indication.GetPktInd()
log.Infow("Received pakcet indication ", log.Fields{"PktInd": pktInd})
+ go dh.handlePacketIndication(pktInd)
case *oop.Indication_PortStats:
portStats := indication.GetPortStats()
log.Infow("Received port stats indication", log.Fields{"PortStats": portStats})
@@ -311,7 +308,7 @@
log.Errorw("Device info is nil", log.Fields{})
return errors.New("Failed to get device info from OLT")
}
-
+ log.Debugw("Fetched device info", log.Fields{"deviceInfo": deviceInfo})
dh.device.Root = true
dh.device.Vendor = deviceInfo.Vendor
dh.device.Model = deviceInfo.Model
@@ -319,7 +316,7 @@
dh.device.SerialNumber = deviceInfo.DeviceSerialNumber
dh.device.HardwareVersion = deviceInfo.HardwareVersion
dh.device.FirmwareVersion = deviceInfo.FirmwareVersion
- // TODO : Check whether this MAC address is learnt from SDPON or need to send from device
+ // FIXME: Remove Hardcodings
dh.device.MacAddress = "0a:0b:0c:0d:0e:0f"
// Synchronous call to update device - this method is run in its own go routine
@@ -394,10 +391,10 @@
func (dh *DeviceHandler) omciIndication(omciInd *oop.OmciIndication) error {
log.Debugw("omci indication", log.Fields{"intfId": omciInd.IntfId, "onuId": omciInd.OnuId})
- // ponPort := IntfIdToPortNo(omciInd.GetIntfId(),voltha.Port_PON_OLT)
+ ponPort := IntfIdToPortNo(omciInd.GetIntfId(), voltha.Port_PON_OLT)
kwargs := make(map[string]interface{})
kwargs["onu_id"] = omciInd.OnuId
- kwargs["parent_port_no"] = omciInd.GetIntfId()
+ kwargs["parent_port_no"] = ponPort
if onuDevice, err := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs); err != nil {
log.Errorw("onu not found", log.Fields{"intfId": omciInd.IntfId, "onuId": omciInd.OnuId})
@@ -416,7 +413,6 @@
// Process_inter_adapter_message process inter adater message
func (dh *DeviceHandler) Process_inter_adapter_message(msg *ic.InterAdapterMessage) error {
- // TODO
log.Debugw("Process_inter_adapter_message", log.Fields{"msgId": msg.Header.Id})
if msg.Header.Type == ic.InterAdapterMessageType_OMCI_REQUEST {
msgId := msg.Header.Id
@@ -462,6 +458,7 @@
func (dh *DeviceHandler) activateONU(intfId uint32, onuId int64, serialNum *oop.SerialNumber, serialNumber string) {
log.Debugw("activate-onu", log.Fields{"intfId": intfId, "onuId": onuId, "serialNum": serialNum, "serialNumber": serialNumber})
+ dh.flowMgr.UpdateOnuInfo(intfId, uint32(onuId), serialNumber)
// TODO: need resource manager
var pir uint32 = 1000000
Onu := oop.Onu{IntfId: intfId, OnuId: uint32(onuId), SerialNumber: serialNum, Pir: pir}
@@ -473,10 +470,8 @@
}
func (dh *DeviceHandler) onuDiscIndication(onuDiscInd *oop.OnuDiscIndication, onuId uint32, sn string) error {
- //channelId := MkUniPortNum(onuDiscInd.GetIntfId(), onuId, uint32(0))
- //parentPortNo := IntfIdToPortNo(onuDiscInd.GetIntfId(),voltha.Port_PON_OLT)
channelId := onuDiscInd.GetIntfId()
- parentPortNo := onuDiscInd.GetIntfId()
+ parentPortNo := IntfIdToPortNo(onuDiscInd.GetIntfId(), voltha.Port_PON_OLT)
if err := dh.coreProxy.ChildDeviceDetected(nil, dh.device.Id, int(parentPortNo), "brcm_openomci_onu", int(channelId), string(onuDiscInd.SerialNumber.GetVendorId()), sn, int64(onuId)); err != nil {
log.Errorw("Create onu error", log.Fields{"parent_id": dh.device.Id, "ponPort": onuDiscInd.GetIntfId(), "onuId": onuId, "sn": sn, "error": err})
return err
@@ -484,7 +479,7 @@
kwargs := make(map[string]interface{})
kwargs["onu_id"] = onuId
- kwargs["parent_port_no"] = onuDiscInd.GetIntfId()
+ kwargs["parent_port_no"] = parentPortNo
for i := 0; i < 10; i++ {
if onuDevice, _ := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs); onuDevice != nil {
@@ -503,19 +498,18 @@
serialNumber := dh.stringifySerialNumber(onuInd.SerialNumber)
kwargs := make(map[string]interface{})
- // ponPort := IntfIdToPortNo(onuInd.GetIntfId(),voltha.Port_PON_OLT)
+ ponPort := IntfIdToPortNo(onuInd.GetIntfId(), voltha.Port_PON_OLT)
if serialNumber != "" {
kwargs["serial_number"] = serialNumber
} else {
kwargs["onu_id"] = onuInd.OnuId
- kwargs["parent_port_no"] = onuInd.GetIntfId()
+ kwargs["parent_port_no"] = ponPort
}
if onuDevice, _ := dh.coreProxy.GetChildDevice(nil, dh.device.Id, kwargs); onuDevice != nil {
- //if intfIdFromPortNo(onuDevice.ParentPortNo) != onuInd.GetIntfId() {
- if onuDevice.ParentPortNo != onuInd.GetIntfId() {
+ if onuDevice.ParentPortNo != ponPort {
//log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": intfIdFromPortNo(onuDevice.ParentPortNo), "currentIntfId": onuInd.GetIntfId()})
- log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": onuInd.GetIntfId()})
+ log.Warnw("ONU-is-on-a-different-intf-id-now", log.Fields{"previousIntfId": onuDevice.ParentPortNo, "currentIntfId": ponPort})
}
if onuDevice.ProxyAddress.OnuId != onuInd.OnuId {
@@ -608,6 +602,15 @@
return onuDevice
}
+func (dh *DeviceHandler) SendPacketInToCore(logicalPort uint32, packetPayload []byte) {
+ log.Debugw("SendPacketInToCore", log.Fields{"port": logicalPort, "packetPayload": packetPayload})
+ if err := dh.coreProxy.SendPacketIn(nil, dh.device.Id, logicalPort, packetPayload); err != nil {
+ log.Errorw("Error sending packetin to core", log.Fields{"error": err})
+ return
+ }
+ log.Debug("Sent packet-in to core successfully")
+}
+
func (dh *DeviceHandler) UpdateFlowsIncrementally(device *voltha.Device, flows *of.FlowChanges, groups *of.FlowGroupChanges) error {
log.Debugw("In UpdateFlowsIncrementally", log.Fields{"deviceId": device.Id, "flows": flows, "groups": groups})
if flows != nil {
@@ -683,3 +686,73 @@
return nil
}
+
+func (dh *DeviceHandler) handlePacketIndication(packetIn *oop.PacketIndication) {
+ log.Debugw("Received packet-in", log.Fields{"packet-indication": *packetIn})
+ logicalPortNum, err := dh.flowMgr.GetLogicalPortFromPacketIn(packetIn)
+ if err != nil {
+ log.Errorw("Error getting logical port from packet-in", log.Fields{"error": err})
+ return
+ }
+ log.Debugw("sending packet-in to core", log.Fields{"logicalPortNum": logicalPortNum, "packet": *packetIn})
+ if err := dh.coreProxy.SendPacketIn(nil, dh.device.Id, logicalPortNum, packetIn.Pkt); err != nil {
+ log.Errorw("Error sending packet-in to core", log.Fields{"error": err})
+ return
+ }
+ log.Debug("Success sending packet-in to core!")
+}
+
+func (dh *DeviceHandler) PacketOut(egress_port_no int, packet *of.OfpPacketOut) error {
+ log.Debugw("PacketOut", log.Fields{"deviceId": dh.deviceId, "egress_port_no": egress_port_no, "pkt-length": len(packet.Data)})
+ var etherFrame ethernet.Frame
+ err := (ðerFrame).UnmarshalBinary(packet.Data)
+ if err != nil {
+ log.Errorw("Failed to unmarshal into ethernet frame", log.Fields{"err": err, "pkt-length": len(packet.Data)})
+ return err
+ }
+ log.Debugw("Ethernet Frame", log.Fields{"Frame": etherFrame})
+ egressPortType := IntfIdToPortTypeName(uint32(egress_port_no))
+ if egressPortType == voltha.Port_ETHERNET_UNI {
+ if etherFrame.VLAN != nil { // If double tag, remove the outer tag
+ nextEthType := (uint16(packet.Data[16]) << 8) | uint16(packet.Data[17])
+ if nextEthType == 0x8100 {
+ etherFrame.VLAN = nil
+ packet.Data, err = etherFrame.MarshalBinary()
+ if err != nil {
+ log.Fatalf("failed to marshal frame: %v", err)
+ return err
+ }
+ if err := (ðerFrame).UnmarshalBinary(packet.Data); err != nil {
+ log.Fatalf("failed to unmarshal frame: %v", err)
+ return err
+ }
+ log.Debug("Double tagged packet , removed outer vlan", log.Fields{"New frame": etherFrame})
+ }
+ }
+ intfId := IntfIdFromUniPortNum(uint32(egress_port_no))
+ onuId := OnuIdFromPortNum(uint32(egress_port_no))
+ uniId := UniIdFromPortNum(uint32(egress_port_no))
+ /*gemPortId, err := dh.flowMgr.GetPacketOutGemPortId(intfId, onuId, uint32(egress_port_no))
+ if err != nil{
+ log.Errorw("Error while getting gemport to packet-out",log.Fields{"error": err})
+ return err
+ }*/
+ onuPkt := oop.OnuPacket{IntfId: intfId, OnuId: onuId, PortNo: uint32(egress_port_no), Pkt: packet.Data}
+ log.Debug("sending-packet-to-ONU", log.Fields{"egress_port_no": egress_port_no, "IntfId": intfId, "onuId": onuId,
+ "uniId": uniId, "packet": packet.Data})
+ if _, err := dh.Client.OnuPacketOut(context.Background(), &onuPkt); err != nil {
+ log.Errorw("Error while sending packet-out to ONU", log.Fields{"error": err})
+ return err
+ }
+ } else if egressPortType == voltha.Port_ETHERNET_NNI {
+ uplinkPkt := oop.UplinkPacket{IntfId: IntfIdFromNniPortNum(uint32(egress_port_no)), Pkt: packet.Data}
+ log.Debug("sending-packet-to-uplink", log.Fields{"uplink_pkt": uplinkPkt})
+ if _, err := dh.Client.UplinkPacketOut(context.Background(), &uplinkPkt); err != nil {
+ log.Errorw("Error while sending packet-out to uplink", log.Fields{"error": err})
+ return err
+ }
+ } else {
+ log.Warnw("Packet-out-to-this-interface-type-not-implemented", log.Fields{"egress_port_no": egress_port_no, "egressPortType": egressPortType})
+ }
+ return nil
+}
diff --git a/adaptercore/olt_platform.go b/adaptercore/olt_platform.go
index 131234a..4cc4765 100644
--- a/adaptercore/olt_platform.go
+++ b/adaptercore/olt_platform.go
@@ -129,7 +129,7 @@
if (intfId & (1 << 16)) == (1 << 16) {
return voltha.Port_ETHERNET_NNI
} else {
- return voltha.Port_UNKNOWN
+ return voltha.Port_ETHERNET_UNI
}
}
}
diff --git a/adaptercore/openolt.go b/adaptercore/openolt.go
index 2e5174f..594ceb3 100644
--- a/adaptercore/openolt.go
+++ b/adaptercore/openolt.go
@@ -210,7 +210,7 @@
return errors.New("UnImplemented")
}
-func (oo *OpenOLT) Gelete_device(device *voltha.Device) error {
+func (oo *OpenOLT) Delete_device(device *voltha.Device) error {
return errors.New("UnImplemented")
}
@@ -235,8 +235,13 @@
return errors.New("UnImplemented")
}
-func (oo *OpenOLT) Receive_packet_out(device *voltha.Device, egress_port_no int, msg openflow_13.PacketOut) error {
- return errors.New("UnImplemented")
+func (oo *OpenOLT) Receive_packet_out(deviceId string, egress_port_no int, packet *openflow_13.OfpPacketOut) error {
+ log.Debugw("Receive_packet_out", log.Fields{"deviceId": deviceId, "egress_port_no": egress_port_no, "pkt": packet})
+ if handler := oo.getDeviceHandler(deviceId); handler != nil {
+ return handler.PacketOut(egress_port_no, packet)
+ }
+ log.Errorw("Receive_packet_out failed-device-handler-not-set", log.Fields{"deviceId": deviceId, "egressport": egress_port_no, "packet": packet})
+ return errors.New("device-handler-not-set")
}
func (oo *OpenOLT) Suppress_alarm(filter *voltha.AlarmFilter) error {
diff --git a/adaptercore/openolt_flowmgr.go b/adaptercore/openolt_flowmgr.go
index 0b8120b..8d9361e 100644
--- a/adaptercore/openolt_flowmgr.go
+++ b/adaptercore/openolt_flowmgr.go
@@ -80,10 +80,36 @@
TRAP_TO_HOST = "trap_to_host"
)
+type onuInfo struct {
+ intfId uint32
+ onuId uint32
+ serialNumber string
+}
+
+type onuIdKey struct {
+ intfId uint32
+ onuId uint32
+}
+
+type gemPortKey struct {
+ intfId uint32
+ gemPort uint32
+}
+
+type packetInInfoKey struct {
+ intfId uint32
+ onuId uint32
+ logicalPort uint32
+}
+
type OpenOltFlowMgr struct {
- techprofile []*tp.TechProfileMgr
- deviceHandler *DeviceHandler
- resourceMgr *rsrcMgr.OpenOltResourceMgr
+ techprofile []*tp.TechProfileMgr
+ deviceHandler *DeviceHandler
+ resourceMgr *rsrcMgr.OpenOltResourceMgr
+ onuIds map[onuIdKey]onuInfo //OnuId -> OnuInfo
+ onuSerialNumbers map[string]onuInfo //onu serial_number (string) -> OnuInfo
+ onuGemPortIds map[gemPortKey]onuInfo //GemPortId -> OnuInfo
+ packetInGemPort map[packetInInfoKey]uint32 //packet in gem port
}
func NewFlowManager(dh *DeviceHandler, rsrcMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
@@ -95,6 +121,10 @@
log.Error("Error while populating tech profile mgr\n")
return nil
}
+ flowMgr.onuIds = make(map[onuIdKey]onuInfo)
+ flowMgr.onuSerialNumbers = make(map[string]onuInfo)
+ flowMgr.onuGemPortIds = make(map[gemPortKey]onuInfo)
+ flowMgr.packetInGemPort = make(map[packetInInfoKey]uint32)
log.Info("Initialization of flow manager success!!")
return &flowMgr
}
@@ -238,6 +268,9 @@
log.Error("Errow while uploading gemtopon map to KV store")
}
log.Debug("Stored tconts and GEM into KV store successfully")
+ for _, gemPort := range gemPortIDs {
+ f.addGemPortToOnuInfoMap(intfId, onuId, gemPort)
+ }
}
func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
@@ -357,8 +390,8 @@
}
action[TRAP_TO_HOST] = true
- classifier[UDP_SRC] = 68
- classifier[UDP_DST] = 67
+ classifier[UDP_SRC] = uint32(68)
+ classifier[UDP_DST] = uint32(67)
classifier[PACKET_TAG_TYPE] = SINGLE_TAG
delete(classifier, VLAN_VID)
@@ -557,7 +590,7 @@
classifier.IpProto = ipProto.(uint32)
}
if vlanId, ok := classifierInfo[VLAN_VID]; ok {
- classifier.OVid = vlanId.(uint32)
+ classifier.OVid = (vlanId.(uint32)) & 0xFFF
}
if metadata, ok := classifierInfo[METADATA]; ok { // TODO: Revisit
classifier.IVid = uint32(metadata.(uint64))
@@ -647,8 +680,17 @@
func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
- // Get existing flow for flowid for given subscriber from KV store
- existingFlows := f.resourceMgr.GetFlowIDInfo(uint32(flow.AccessIntfId), uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
+ var intfId uint32
+ /* For flows which trap out of the NNI, the AccessIntfId is invalid
+ (set to -1). In such cases, we need to refer to the NetworkIntfId .
+ */
+ if flow.AccessIntfId != -1 {
+ intfId = uint32(flow.AccessIntfId)
+ } else {
+ intfId = uint32(flow.NetworkIntfId)
+ }
+ // Get existing flows matching flowid for given subscriber from KV store
+ existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
if existingFlows != nil {
log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
for _, f := range *existingFlows {
@@ -709,8 +751,7 @@
func (f *OpenOltFlowMgr) getOnuChildDevice(intfId uint32, onuId uint32) (*voltha.Device, error) {
log.Debugw("GetChildDevice", log.Fields{"pon port": intfId, "onuId": onuId})
- //parentPortNo := IntfIdToPortNo(intfId, voltha.Port_PON_OLT)
- parentPortNo := intfId
+ parentPortNo := IntfIdToPortNo(intfId, voltha.Port_PON_OLT)
onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuId)
if onuDevice == nil {
log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuId})
@@ -867,6 +908,17 @@
}
log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[IN_PORT], "action_output": actionInfo[OUTPUT]})
portNo, intfId, onuId, uniId := ExtractAccessFromFlow(classifierInfo[IN_PORT].(uint32), actionInfo[OUTPUT].(uint32))
+ if ipProto, ok := classifierInfo[IP_PROTO]; ok {
+ if ipProto.(uint32) == IP_PROTO_DHCP {
+ if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
+ if udpSrc.(uint32) == uint32(67) {
+ log.Debug("trap-dhcp-from-nni-flow")
+ f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
+ return
+ }
+ }
+ }
+ }
f.divideAndAddFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow)
}
@@ -898,3 +950,153 @@
log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
return nil
}
+
+// This function adds onu info to cache
+func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
+ onu := onuInfo{intfId: intfID, onuId: onuID, serialNumber: serialNum}
+ onuIDkey := onuIdKey{intfId: intfID, onuId: onuID}
+ f.onuIds[onuIDkey] = onu
+ log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
+}
+
+// This function stores adds GEMport to ONU map
+func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfId uint32, onuId uint32, gemPort uint32) {
+ onuIDkey := onuIdKey{intfId: intfId, onuId: onuId}
+ if val, ok := f.onuIds[onuIDkey]; ok {
+ onuInfo := val
+ gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPort}
+ f.onuGemPortIds[gemPortKey] = onuInfo
+ log.Debugw("Cached Gemport to Onuinfo map", log.Fields{"GemPort": gemPort, "intfId": onuInfo.intfId, "onuId": onuInfo.onuId})
+ return
+ }
+ log.Errorw("OnuInfo not found", log.Fields{"intfId": intfId, "onuId": onuId, "gemPort": gemPort})
+}
+
+// This function Lookup maps by serialNumber or (intfId, gemPort)
+// Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
+func (f *OpenOltFlowMgr) getOnuIdfromGemPortMap(serialNumber string, intfId uint32, gemPortId uint32) (uint32, error) {
+ log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPortId": gemPortId})
+ if serialNumber != "" {
+ if onuInfo, ok := f.onuSerialNumbers[serialNumber]; ok {
+ return onuInfo.onuId, nil
+ }
+ } else {
+ gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPortId}
+ if onuInfo, ok := f.onuGemPortIds[gemPortKey]; ok {
+ log.Debugw("Retrived onu info from access", log.Fields{"intfId": intfId, "gemPortId": gemPortId, "onuId": onuInfo.onuId})
+ return onuInfo.onuId, nil
+ }
+ }
+ log.Errorw("ONU ID is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPort": gemPortId})
+ return uint32(0), errors.New("Key Error ,ONU ID is not found") // ONU ID 0 is not a valid one
+}
+
+// This function computes logical port UNI/NNI port from packet-in indication and returns the same
+func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openolt_pb2.PacketIndication) (uint32, error) {
+ var logicalPortNum uint32
+ var onuId uint32
+ var err error
+
+ if packetIn.IntfType == "pon" {
+ // packet indication does not have serial number , so sending as nil
+ if onuId, err = f.getOnuIdfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
+ log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
+ return logicalPortNum, err
+ }
+ if packetIn.PortNo != 0 {
+ logicalPortNum = packetIn.PortNo
+ } else {
+ uniId := uint32(0) // FIXME - multi-uni support
+ logicalPortNum = MkUniPortNum(packetIn.IntfId, onuId, uniId)
+ }
+ // Store the gem port through which the packet_in came. Use the same gem port for packet_out
+ pktInkey := packetInInfoKey{intfId: packetIn.IntfId, onuId: onuId, logicalPort: logicalPortNum}
+ f.packetInGemPort[pktInkey] = packetIn.GemportId
+ } else if packetIn.IntfType == "nni" {
+ logicalPortNum = IntfIdToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
+ }
+ log.Debugw("Retrieved logicalport from packet-in", log.Fields{"logicalPortNum": logicalPortNum, "IntfType": packetIn.IntfType})
+ return logicalPortNum, nil
+}
+
+func (f *OpenOltFlowMgr) GetPacketOutGemPortId(intfId uint32, onuId uint32, portNum uint32) (uint32, error) {
+ var gemPortId uint32
+ var err error
+ key := packetInInfoKey{intfId: intfId, onuId: onuId, logicalPort: portNum}
+ if val, ok := f.packetInGemPort[key]; ok {
+ gemPortId = val
+ } else {
+ log.Errorw("Key-Error while fetching packet-out GEM port", log.Fields{"key": key})
+ err = errors.New("Key-Error while fetching packet-out GEM port")
+ }
+ return gemPortId, err
+}
+
+func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
+ log.Debug("Adding trap-dhcp-of-nni-flow")
+ action := make(map[string]interface{})
+ classifier[PACKET_TAG_TYPE] = DOUBLE_TAG
+ action[TRAP_TO_HOST] = true
+ /* We manage flowId resource pool on per PON port basis.
+ Since this situation is tricky, as a hack, we pass the NNI port
+ index (network_intf_id) as PON port Index for the flowId resource
+ pool. Also, there is no ONU Id available for trapping DHCP packets
+ on NNI port, use onu_id as -1 (invalid)
+ ****************** CAVEAT *******************
+ This logic works if the NNI Port Id falls within the same valid
+ range of PON Port Ids. If this doesn't work for some OLT Vendor
+ we need to have a re-look at this.
+ *********************************************
+ */
+ onuId := -1
+ uniId := -1
+ gemPortId := -1
+ allocId := -1
+ networkInterfaceId := DEFAULT_NETWORK_INTERFACE_ID
+ flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
+ if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie); present {
+ log.Debug("Flow-exists--not-re-adding")
+ return
+ }
+ flowId, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie, "")
+ if err != nil {
+ log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
+ return
+ }
+ var classifierProto *openolt_pb2.Classifier
+ var actionProto *openolt_pb2.Action
+ if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
+ log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
+ return
+ }
+ log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
+ if actionProto = makeOpenOltActionField(action); actionProto == nil {
+ log.Error("Error in making action protobuf for dhcp trap on nni flow")
+ return
+ }
+ log.Debugw("Created action proto", log.Fields{"action": *actionProto})
+ downstreamflow := openolt_pb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
+ OnuId: int32(onuId), // OnuId not required
+ UniId: int32(uniId), // UniId not used
+ FlowId: flowId,
+ FlowType: DOWNSTREAM,
+ AllocId: int32(allocId), // AllocId not used
+ NetworkIntfId: DEFAULT_NETWORK_INTERFACE_ID, // one NNI port is supported now
+ GemportId: int32(gemPortId), // GemportId not used
+ Classifier: classifierProto,
+ Action: actionProto,
+ Priority: int32(logicalFlow.Priority),
+ Cookie: logicalFlow.Cookie,
+ PortNo: portNo}
+ if ok := f.addFlowToDevice(&downstreamflow); ok {
+ log.Debug("DHCP trap on NNI flow added to device successfully")
+ flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "")
+ if err := f.updateFlowInfoToKVStore(int32(networkInterfaceId),
+ int32(onuId),
+ int32(uniId),
+ flowId, flowsToKVStore); err != nil {
+ log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
+ }
+ }
+ return
+}
diff --git a/adaptercore/resourcemanager/resourcemanager.go b/adaptercore/resourcemanager/resourcemanager.go
index 2bd84a7..f87ffd1 100755
--- a/adaptercore/resourcemanager/resourcemanager.go
+++ b/adaptercore/resourcemanager/resourcemanager.go
@@ -170,7 +170,7 @@
if GlobalPONRsrcMgr == nil {
GlobalPONRsrcMgr = RsrcMgrsByTech[technology]
}
- for IntfId := range TechRange.IntfIds {
+ for _, IntfId := range TechRange.IntfIds {
ResourceMgr.ResourceMgrs[uint32(IntfId)] = RsrcMgrsByTech[technology]
}
//self.initialize_device_resource_range_and_pool(resource_mgr, global_resource_mgr, arange)
@@ -222,17 +222,24 @@
FlowIDShared := openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH // TODO EdgeCore/BAL limitation
FlowIDSharedPoolID := uint32(0)
- var GlobalPoolID uint32
var FirstIntfPoolID uint32
var SharedPoolID uint32
+ /*
+ * As a zero check is made against SharedPoolID to check whether the resources are shared across all intfs
+ * if resources are shared accross interfaces then SharedPoolID is given a positive number.
+ */
for _, FirstIntfPoolID = range TechRange.IntfIds {
+ // skip the intf id 0
+ if FirstIntfPoolID == 0 {
+ continue
+ }
break
}
for _, RangePool := range TechRange.Pools {
if RangePool.Sharing == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH {
- SharedPoolID = GlobalPoolID
+ SharedPoolID = FirstIntfPoolID
} else if RangePool.Sharing == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_SAME_TECH {
SharedPoolID = FirstIntfPoolID
} else {
@@ -406,7 +413,6 @@
for _, flowId := range FlowIDs {
FlowInfo := RsrcMgr.GetFlowIDInfo(PONIntfID, ONUID, UNIID, uint32(flowId))
if FlowInfo != nil {
- log.Debugw("Found flows", log.Fields{"flows": *FlowInfo, "flowId": flowId})
for _, Info := range *FlowInfo {
if FlowCategory != "" && Info.FlowCategory == FlowCategory {
log.Debug("Found flow matching with flow catagory", log.Fields{"flowId": flowId, "FlowCategory": FlowCategory})
@@ -426,7 +432,7 @@
if err != nil {
log.Errorf("Failed to get resource for interface %d for type %s",
PONIntfID, ponrmgr.FLOW_ID)
- return FlowIDs[0], err
+ return uint32(0), err
}
if FlowIDs != nil {
RsrcMgr.ResourceMgrs[PONIntfID].UpdateFlowIDForOnu(FlowPath, FlowIDs[0], true)
@@ -672,25 +678,25 @@
}
}
-/* TODO once the flow id info structure is known
-def is_flow_cookie_on_kv_store(self, intf_id, onu_id, uni_id, flow_store_cookie):
- '''
- Note: For flows which trap from the NNI and not really associated with any particular
- ONU (like LLDP), the onu_id and uni_id is set as -1. The intf_id is the NNI intf_id.
- '''
- intf_onu_id = (intf_id, onu_id, uni_id)
- try:
- flow_ids = self.resource_mgrs[intf_id]. \
- get_current_flow_ids_for_onu(intf_onu_id)
- if flow_ids is not None:
- for flow_id in flow_ids:
- flows = self.get_flow_id_info(intf_id, onu_id, uni_id, flow_id)
- assert (isinstance(flows, list))
- for flow in flows:
- if flow['flow_store_cookie'] == flow_store_cookie:
- return True
- except Exception as e:
- self.log.error("error-retrieving-flow-info", e=e)
+func (RsrcMgr *OpenOltResourceMgr) IsFlowCookieOnKVStore(PONIntfID uint32, ONUID uint32, UNIID uint32,
+ FlowStoreCookie uint64) bool {
- return False
-*/
+ FlowPath := fmt.Sprintf("%d,%d,%d", PONIntfID, ONUID, UNIID)
+ FlowIDs := RsrcMgr.ResourceMgrs[PONIntfID].GetCurrentFlowIDsForOnu(FlowPath)
+ if FlowIDs != nil {
+ log.Debugw("Found flowId(s) for this ONU", log.Fields{"pon": PONIntfID, "ONUID": ONUID, "UNIID": UNIID, "KVpath": FlowPath})
+ for _, flowId := range FlowIDs {
+ FlowInfo := RsrcMgr.GetFlowIDInfo(PONIntfID, ONUID, UNIID, uint32(flowId))
+ if FlowInfo != nil {
+ log.Debugw("Found flows", log.Fields{"flows": *FlowInfo, "flowId": flowId})
+ for _, Info := range *FlowInfo {
+ if Info.FlowStoreCookie == FlowStoreCookie {
+ log.Debug("Found flow matching with flowStore cookie", log.Fields{"flowId": flowId, "FlowStoreCookie": FlowStoreCookie})
+ return true
+ }
+ }
+ }
+ }
+ }
+ return false
+}