VOL-1878 : Support for LLDP trap flow in OpenOLT adapter
Changes are done to handle LLDP flow implementation.
This commit has dependency on voltha-go, so that needs to
be merged first. Please find the review link
https://gerrit.opencord.org/#/c/15062/
Rebased and fixed sca issue.
Change-Id: I4ce886f68f6f90767eb73cbfa9bd5a25fbcbfb08
diff --git a/adaptercore/olt_platform.go b/adaptercore/olt_platform.go
index 5540392..a75c25d 100644
--- a/adaptercore/olt_platform.go
+++ b/adaptercore/olt_platform.go
@@ -176,12 +176,14 @@
return (portNum >> 4) & 0x7F
}
-//FlowExtractInfo fetches uniport from the flow, based on which it gets and returns ponInf, onuID and uniID
-func FlowExtractInfo(flow *ofp.OfpFlowStats, flowDirection string) (uint32, uint32, uint32, uint32, error) {
+//FlowExtractInfo fetches uniport from the flow, based on which it gets and returns ponInf, onuID, uniID, inPort and ethType
+func FlowExtractInfo(flow *ofp.OfpFlowStats, flowDirection string) (uint32, uint32, uint32, uint32, uint32, uint32, error) {
var uniPortNo uint32
var ponIntf uint32
var onuID uint32
var uniID uint32
+ var inPort uint32
+ var ethType uint32
if flowDirection == "upstream" {
if uniPortNo = utils.GetChildPortFromTunnelId(flow); uniPortNo == 0 {
@@ -194,24 +196,32 @@
}
} else if flowDirection == "downstream" {
if uniPortNo = utils.GetChildPortFromTunnelId(flow); uniPortNo == 0 {
- for _, action := range utils.GetActions(flow) {
- if action.Type == utils.OUTPUT {
- if out := action.GetOutput(); out != nil {
- uniPortNo = out.GetPort()
+ for _, field := range utils.GetOfbFields(flow) {
+ if field.GetType() == utils.METADATA {
+ for _, action := range utils.GetActions(flow) {
+ if action.Type == utils.OUTPUT {
+ if out := action.GetOutput(); out != nil {
+ uniPortNo = out.GetPort()
+ }
+ break
+ }
}
- break
+ } else if field.GetType() == utils.IN_PORT {
+ inPort = field.GetPort()
+ } else if field.GetType() == utils.ETH_TYPE {
+ ethType = field.GetEthType()
}
}
}
}
if uniPortNo == 0 {
- return 0, 0, 0, 0, errors.New("failed to extract Pon Interface, ONU Id and Uni Id from flow")
+ return 0, 0, 0, 0, 0, 0, errors.New("failed to extract Pon Interface, ONU Id and Uni Id from flow")
}
ponIntf = IntfIDFromUniPortNum(uniPortNo)
onuID = OnuIDFromUniPortNum(uniPortNo)
uniID = UniIDFromPortNum(uniPortNo)
- return uniPortNo, ponIntf, onuID, uniID, nil
+ return uniPortNo, ponIntf, onuID, uniID, inPort, ethType, nil
}
diff --git a/adaptercore/openolt_flowmgr.go b/adaptercore/openolt_flowmgr.go
index 305f6af..e99d36e 100644
--- a/adaptercore/openolt_flowmgr.go
+++ b/adaptercore/openolt_flowmgr.go
@@ -68,7 +68,7 @@
//FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
- // ReservedVlan Transparent Vlan
+ //ReservedVlan Transparent Vlan
ReservedVlan = 4095
//DefaultMgmtVlan default vlan value
@@ -1044,8 +1044,79 @@
*/
-func addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
- log.Info("unimplemented flow : %v, portNo : %v ", flow, portNo)
+func (f *OpenOltFlowMgr) addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
+
+ classifierInfo := make(map[string]interface{})
+ actionInfo := make(map[string]interface{})
+
+ classifierInfo[EthType] = uint32(LldpEthType)
+ classifierInfo[PacketTagType] = Untagged
+ actionInfo[TrapToHost] = true
+
+ // LLDP flow is installed to trap LLDP packets on the NNI port.
+ // We manage flow_id 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 flow_id resource
+ // pool. Also, there is no ONU Id available for trapping LLDP 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.
+ // *********************************************
+
+ var onuID = -1
+ var uniID = -1
+ var gemPortID = -1
+
+ var networkInterfaceID = IntfIDFromNniPortNum(portNo)
+ var flowStoreCookie = getFlowStoreCookie(classifierInfo, 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), uint32(gemPortID), flowStoreCookie, "", 0)
+
+ if err != nil {
+ log.Errorw("Flow id unavailable for LLDP traponNNI flow", log.Fields{"error": err})
+ return
+ }
+ var classifierProto *openoltpb2.Classifier
+ var actionProto *openoltpb2.Action
+ if classifierProto = makeOpenOltClassifierField(classifierInfo); classifierProto == nil {
+ log.Error("Error in making classifier protobuf for LLDP trap on nni flow")
+ return
+ }
+ log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
+ if actionProto = makeOpenOltActionField(actionInfo); actionProto == nil {
+ log.Error("Error in making action protobuf for LLDP trap on nni flow")
+ return
+ }
+ log.Debugw("Created action proto", log.Fields{"action": *actionProto})
+
+ downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
+ OnuId: int32(onuID), // OnuId not required
+ UniId: int32(uniID), // UniId not used
+ FlowId: flowID,
+ FlowType: Downstream,
+ NetworkIntfId: int32(networkInterfaceID),
+ GemportId: int32(gemPortID),
+ Classifier: classifierProto,
+ Action: actionProto,
+ Priority: int32(flow.Priority),
+ Cookie: flow.Cookie,
+ PortNo: portNo}
+ if ok := f.addFlowToDevice(flow, &downstreamflow); ok {
+ log.Debug("LLDP trap on NNI flow added to device successfully")
+ flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowID)
+ if err := f.updateFlowInfoToKVStore(int32(networkInterfaceID),
+ int32(onuID),
+ int32(uniID),
+ flowID, flowsToKVStore); err != nil {
+ log.Errorw("Error uploading LLDP flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
+ }
+ }
+ return
}
func getUniPortPath(intfID uint32, onuID uint32, uniID uint32) string {
@@ -1083,7 +1154,7 @@
func (f *OpenOltFlowMgr) clearFlowFromResourceManager(flow *ofp.OfpFlowStats, flowID uint32, flowDirection string) {
log.Debugw("clearFlowFromResourceManager", log.Fields{"flowID": flowID, "flowDirection": flowDirection, "flow": *flow})
- portNum, ponIntf, onuID, uniID, err := FlowExtractInfo(flow, flowDirection)
+ portNum, ponIntf, onuID, uniID, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
if err != nil {
log.Error(err)
return
@@ -1091,6 +1162,16 @@
log.Debugw("Extracted access info from flow to be deleted",
log.Fields{"ponIntf": ponIntf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
+ if ethType == LldpEthType {
+ var networkInterfaceID uint32
+ var onuID = -1
+ var uniID = -1
+
+ networkInterfaceID = IntfIDFromNniPortNum(inPort)
+ f.resourceMgr.FreeFlowID(networkInterfaceID, int32(onuID), int32(uniID), flowID)
+ return
+ }
+
flowsInfo := f.resourceMgr.GetFlowIDInfo(ponIntf, onuID, uniID, flowID)
if flowsInfo == nil {
log.Debugw("No FlowInfo found found in KV store",
@@ -1214,6 +1295,13 @@
log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
+ if ethType, ok := classifierInfo[EthType]; ok {
+ if ethType.(uint32) == LldpEthType {
+ log.Info("Adding LLDP flow")
+ f.addLLDPFlow(flow, portNo)
+ return
+ }
+ }
if ipProto, ok := classifierInfo[IPProto]; ok {
if ipProto.(uint32) == IPProtoDhcp {
if udpSrc, ok := classifierInfo[UDPSrc]; ok {
@@ -1520,11 +1608,6 @@
installFlowOnAllGemports(nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
}
}
- if ethType == LldpEthType {
- log.Info("Adding LLDP flow")
- addLLDPFlow(flow, portNo)
- return
- }
} else if _, ok := actionInfo[PushVlan]; ok {
log.Info("Adding upstream data rule")
if pcp, ok := classifierInfo[VlanPcp]; ok {