blob: 2b8855a407e32ad07a632f1728e373f99a7ed132 [file] [log] [blame]
manikkaraj kbf256be2019-03-25 00:13:48 +05301/*
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
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070017//Package adaptercore provides the utility for olt devices, flows and statistics
manikkaraj kbf256be2019-03-25 00:13:48 +053018package adaptercore
19
20import (
21 "context"
22 "crypto/md5"
Matteo Scandolo6056e822019-11-13 14:05:29 -080023 "encoding/hex"
manikkaraj kbf256be2019-03-25 00:13:48 +053024 "encoding/json"
manikkaraj kbf256be2019-03-25 00:13:48 +053025 "fmt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040026 "math/big"
William Kurkian740a09c2019-10-23 17:07:38 -040027 "sync"
Girish Gowdra3d633032019-12-10 16:37:05 +053028 "time"
Manikkaraj kb1d51442019-07-23 10:41:02 -040029
Esin Karamanccb714b2019-11-29 15:02:06 +000030 "github.com/opencord/voltha-lib-go/v3/pkg/flows"
31 "github.com/opencord/voltha-lib-go/v3/pkg/log"
32 tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
Manikkaraj k884c1242019-04-11 16:26:42 +053033 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
Esin Karamanccb714b2019-11-29 15:02:06 +000034 "github.com/opencord/voltha-protos/v3/go/common"
35 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
36 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
37 openoltpb2 "github.com/opencord/voltha-protos/v3/go/openolt"
38 tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
39 "github.com/opencord/voltha-protos/v3/go/voltha"
Chaitrashree G S579fe732019-08-20 20:50:47 -040040
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040041 //deepcopy "github.com/getlantern/deepcopy"
Girish Gowdra3d633032019-12-10 16:37:05 +053042 "github.com/EagleChen/mapmutex"
Daniele Rossi22db98e2019-07-11 11:50:00 +000043 "google.golang.org/grpc/codes"
44 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053045)
46
47const (
48 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053049
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070050 //HsiaFlow flow category
51 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053052
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070053 //EapolFlow flow category
54 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053055
Manikkaraj kb1d51442019-07-23 10:41:02 -040056 //DhcpFlow flow category
57 DhcpFlow = "DHCP_FLOW"
58
Esin Karamanccb714b2019-11-29 15:02:06 +000059 //MulticastFlow flow category
60 MulticastFlow = "MULTICAST_FLOW"
61
Esin Karamanae41e2b2019-12-17 18:13:13 +000062 //IgmpFlow flow category
63 IgmpFlow = "IGMP_FLOW"
64
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070065 //IPProtoDhcp flow category
66 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053067
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070068 //IPProtoIgmp flow category
69 IPProtoIgmp = 2
70
71 //EapEthType eapethtype value
72 EapEthType = 0x888e
73 //LldpEthType lldp ethtype value
74 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000075 //IPv4EthType IPv4 ethernet type value
76 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070077
78 //IgmpProto proto value
79 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053080
81 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070082
Humera Kouser94d7a842019-08-25 19:04:32 -040083 //ReservedVlan Transparent Vlan
David K. Bainbridge82efc492019-09-04 09:57:11 -070084 ReservedVlan = 4095
Harsh Awasthiea45af72019-08-26 02:39:00 -040085
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070086 //DefaultMgmtVlan default vlan value
87 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053088
manikkaraj kbf256be2019-03-25 00:13:48 +053089 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070090
David K. Bainbridge82efc492019-09-04 09:57:11 -070091 //Upstream constant
92 Upstream = "upstream"
93 //Downstream constant
94 Downstream = "downstream"
Esin Karamanccb714b2019-11-29 15:02:06 +000095 //Multicast constant
96 Multicast = "multicast"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070097 //PacketTagType constant
98 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -070099 //Untagged constant
100 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700101 //SingleTag constant
102 SingleTag = "single_tag"
103 //DoubleTag constant
104 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530105
106 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700107
108 //EthType constant
109 EthType = "eth_type"
Esin Karamanccb714b2019-11-29 15:02:06 +0000110 //EthDst constant
111 EthDst = "eth_dst"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700112 //TPID constant
113 TPID = "tpid"
114 //IPProto constant
115 IPProto = "ip_proto"
116 //InPort constant
117 InPort = "in_port"
118 //VlanVid constant
119 VlanVid = "vlan_vid"
120 //VlanPcp constant
121 VlanPcp = "vlan_pcp"
122
123 //UDPDst constant
124 UDPDst = "udp_dst"
125 //UDPSrc constant
126 UDPSrc = "udp_src"
127 //Ipv4Dst constant
128 Ipv4Dst = "ipv4_dst"
129 //Ipv4Src constant
130 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700131 //Metadata constant
132 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700133 //TunnelID constant
134 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700135 //Output constant
136 Output = "output"
Esin Karamanccb714b2019-11-29 15:02:06 +0000137 //GroupID constant
138 GroupID = "group_id"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700139 // Actions
140
141 //PopVlan constant
142 PopVlan = "pop_vlan"
143 //PushVlan constant
144 PushVlan = "push_vlan"
145 //TrapToHost constant
146 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400147 //MaxMeterBand constant
148 MaxMeterBand = 2
149 //VlanPCPMask contant
150 VlanPCPMask = 0xFF
151 //VlanvIDMask constant
152 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000153 //IntfID constant
154 IntfID = "intfId"
155 //OnuID constant
156 OnuID = "onuId"
157 //UniID constant
158 UniID = "uniId"
159 //PortNo constant
160 PortNo = "portNo"
161 //AllocID constant
162 AllocID = "allocId"
Esin Karamanccb714b2019-11-29 15:02:06 +0000163
164 //NoneOnuID constant
165 NoneOnuID = -1
166 //NoneUniID constant
167 NoneUniID = -1
168 //NoneGemPortID constant
169 NoneGemPortID = -1
manikkaraj kbf256be2019-03-25 00:13:48 +0530170)
171
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400172type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700173 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400174 gemPort uint32
175}
176
Girish Gowdra3d633032019-12-10 16:37:05 +0530177type pendingFlowDeleteKey struct {
178 intfID uint32
179 onuID uint32
180 uniID uint32
181}
182
183type tpLockKey struct {
184 intfID uint32
185 onuID uint32
186 uniID uint32
187}
188
Gamze Abakafee36392019-10-03 11:17:24 +0000189type schedQueue struct {
190 direction tp_pb.Direction
191 intfID uint32
192 onuID uint32
193 uniID uint32
194 tpID uint32
195 uniPort uint32
196 tpInst *tp.TechProfile
197 meterID uint32
198 flowMetadata *voltha.FlowMetadata
199}
200
Esin Karamanccb714b2019-11-29 15:02:06 +0000201type queueInfoBrief struct {
202 gemPortID uint32
203 servicePriority uint32
204}
205
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700206//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530207type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000208 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000209 deviceHandler *DeviceHandler
210 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000211 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530212 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
213 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
214 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
215 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530216 pendingFlowDelete sync.Map
217 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
Esin Karamanccb714b2019-11-29 15:02:06 +0000218 perUserFlowHandleLock *mapmutex.Mutex
219 interfaceToMcastQueueMap map[uint32]*queueInfoBrief /*pon interface -> multicast queue map. Required to assign GEM to a bucket during group population*/
manikkaraj kbf256be2019-03-25 00:13:48 +0530220}
221
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700222//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
npujarec5762e2020-01-01 14:08:48 +0530223func NewFlowManager(ctx context.Context, dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530224 log.Info("Initializing flow manager")
225 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530226 var err error
227 var idx uint32
228
manikkaraj kbf256be2019-03-25 00:13:48 +0530229 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530230 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000231 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530232 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530233 log.Error("Error while populating tech profile mgr\n")
234 return nil
235 }
William Kurkian740a09c2019-10-23 17:07:38 -0400236 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530237 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
238 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
239 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
240 ponPorts := rMgr.DevInfo.GetPonPorts()
241 //Load the onugem info cache from kv store on flowmanager start
242 for idx = 0; idx < ponPorts; idx++ {
npujarec5762e2020-01-01 14:08:48 +0530243 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(ctx, idx); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530244 log.Error("Failed to load onu gem info cache")
245 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530246 //Load flowID list per gem map per interface from the kvstore.
npujarec5762e2020-01-01 14:08:48 +0530247 flowMgr.loadFlowIDlistForGem(ctx, idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530248 }
249 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530250 flowMgr.pendingFlowDelete = sync.Map{}
251 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
Esin Karamanccb714b2019-11-29 15:02:06 +0000252 flowMgr.interfaceToMcastQueueMap = make(map[uint32]*queueInfoBrief)
253 //load interface to multicast queue map from kv store
npujarec5762e2020-01-01 14:08:48 +0530254 flowMgr.loadInterfaceToMulticastQueueMap(ctx)
manikkaraj kbf256be2019-03-25 00:13:48 +0530255 log.Info("Initialization of flow manager success!!")
256 return &flowMgr
257}
258
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700259func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700260 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400261 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700262 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700263 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400264 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700265 return uint64(flowID), nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000266 } else if direction == Multicast {
267 log.Debug("multicast flow, shifting id")
268 return 0x2<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400269 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800270 return 0, NewErrInvalidValue(log.Fields{"direction": direction}, nil).Log()
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400271 }
272}
273
npujarec5762e2020-01-01 14:08:48 +0530274func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400275 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700276 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000277 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
278 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
279 if !ok {
280 flowIDList = []uint32{deviceFlow.FlowId}
281 }
282 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
283 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530284 // update the flowids for a gem to the KVstore
npujarec5762e2020-01-01 14:08:48 +0530285 f.resourceMgr.UpdateFlowIDsForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400286}
287
npujarec5762e2020-01-01 14:08:48 +0530288func (f *OpenOltFlowMgr) divideAndAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000289 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
290 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000291 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530292 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400293 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530294
Manikkaraj kb1d51442019-07-23 10:41:02 -0400295 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000296 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400297 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
298 // is because the flow is an NNI flow and there would be no onu resources associated with it
299 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400300 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400301 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530302 return
303 }
304
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530305 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400306 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530307
308 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
309 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
npujarec5762e2020-01-01 14:08:48 +0530310 allocID, gemPorts, TpInst = f.createTcontGemports(ctx, intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +0530311 if allocID == 0 || gemPorts == nil || TpInst == nil {
312 log.Error("alloc-id-gem-ports-tp-unavailable")
313 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
314 return
315 }
316 args := make(map[string]uint32)
317 args[IntfID] = intfID
318 args[OnuID] = onuID
319 args[UniID] = uniID
320 args[PortNo] = portNo
321 args[AllocID] = allocID
322
323 /* Flows can be added specific to gemport if p-bits are received.
324 * If no pbit mentioned then adding flows for all gemports
325 */
npujarec5762e2020-01-01 14:08:48 +0530326 f.checkAndAddFlow(ctx, args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
Girish Gowdra3d633032019-12-10 16:37:05 +0530327 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
328 } else {
329 log.Errorw("failed to acquire per user flow handle lock",
330 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400331 return
332 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530333}
334
salmansiddiqui7ac62132019-08-22 03:58:50 +0000335// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530336func (f *OpenOltFlowMgr) CreateSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400337
Gamze Abakafee36392019-10-03 11:17:24 +0000338 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
339 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
340 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400341
Gamze Abakafee36392019-10-03 11:17:24 +0000342 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000343 if err != nil {
344 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400345 }
346
347 /* Lets make a simple assumption that if the meter-id is present on the KV store,
348 * then the scheduler and queues configuration is applied on the OLT device
349 * in the given direction.
350 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000351
Manikkaraj kb1d51442019-07-23 10:41:02 -0400352 var SchedCfg *tp_pb.SchedulerConfig
npujarec5762e2020-01-01 14:08:48 +0530353 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400354 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000355 log.Error("Failed to get meter for intf %d, onuid %d, uniid %d", sq.intfID, sq.onuID, sq.uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400356 return err
357 }
358 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000359 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400360 log.Debug("Scheduler already created for upstream")
361 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400362 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800363 return NewErrInvalidValue(log.Fields{
364 "unsupported": "meter-id",
365 "kv-store-meter-id": KvStoreMeter.MeterId,
366 "meter-id-in-flow": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400367 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000368
Gamze Abakafee36392019-10-03 11:17:24 +0000369 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000370
Gamze Abakafee36392019-10-03 11:17:24 +0000371 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000372 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000373 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000374 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400375 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000376
377 if err != nil {
378 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
379 return err
380 }
381
Manikkaraj kb1d51442019-07-23 10:41:02 -0400382 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000383 if sq.flowMetadata != nil {
384 for _, meter := range sq.flowMetadata.Meters {
385 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400386 meterConfig = meter
387 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
388 break
389 }
390 }
391 } else {
392 log.Error("Flow-metadata-is-not-present-in-flow")
393 }
394 if meterConfig == nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800395 return NewErrNotFound("meterbands", log.Fields{
396 "reason": "Could-not-get-meterbands-from-flowMetadata",
397 "flow-metadata": sq.flowMetadata,
398 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400399 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000400 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800401 return NewErrInvalidValue(log.Fields{
402 "reason": "Invalid-number-of-bands-in-meter",
403 "meterband-count": len(meterConfig.Bands),
404 "metabands": meterConfig.Bands,
405 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400406 }
407 cir := meterConfig.Bands[0].Rate
408 cbs := meterConfig.Bands[0].BurstSize
409 eir := meterConfig.Bands[1].Rate
410 ebs := meterConfig.Bands[1].BurstSize
411 pir := cir + eir
412 pbs := cbs + ebs
413 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
414
Gamze Abakafee36392019-10-03 11:17:24 +0000415 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400416
npujarec5762e2020-01-01 14:08:48 +0530417 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000418 log.Errorw("Failed to push traffic scheduler and queues to device", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400419 return err
420 }
421
salmansiddiqui7ac62132019-08-22 03:58:50 +0000422 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400423 * store the meter id on the KV store, for further reference.
424 */
npujarec5762e2020-01-01 14:08:48 +0530425 if err := f.resourceMgr.UpdateMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID, meterConfig); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000426 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400427 return err
428 }
429 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
430 "Meter": meterConfig})
431 return nil
432}
433
npujarec5762e2020-01-01 14:08:48 +0530434func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000435
436 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
437
438 if err != nil {
439 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
440 return err
441 }
442
443 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530444 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000445 IntfId: sq.intfID, OnuId: sq.onuID,
446 UniId: sq.uniID, PortNo: sq.uniPort,
447 TrafficScheds: TrafficSched}); err != nil {
448 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
449 return err
450 }
451
452 // On receiving the CreateTrafficQueues request, the driver should create corresponding
453 // downstream queues.
454 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530455 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000456 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
457 UniId: sq.uniID, PortNo: sq.uniPort,
458 TrafficQueues: trafficQueues}); err != nil {
459 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
460 return err
461 }
462
Esin Karamanccb714b2019-11-29 15:02:06 +0000463 if sq.direction == tp_pb.Direction_DOWNSTREAM {
464 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
465 if len(multicastTrafficQueues) > 0 {
466 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
467 //assumed that there is only one queue per PON for the multicast service
468 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
469 //just put it in interfaceToMcastQueueMap to use for building group members
470 multicastQueuePerPonPort := multicastTrafficQueues[0]
471 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
472 gemPortID: multicastQueuePerPonPort.GemportId,
473 servicePriority: multicastQueuePerPonPort.Priority,
474 }
475 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530476 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000477 multicastQueuePerPonPort.GemportId,
478 multicastQueuePerPonPort.Priority)
479 }
480 }
481 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000482 return nil
483}
484
salmansiddiqui7ac62132019-08-22 03:58:50 +0000485// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530486func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400487
488 var Direction string
489 var SchedCfg *tp_pb.SchedulerConfig
490 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000491 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
492 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
493 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000494 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400495 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000496 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000497 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400498 Direction = "downstream"
499 }
500
Girish Kumar8f73fe02019-12-09 13:19:37 +0000501 if err != nil {
502 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
503 return err
504 }
505
npujarec5762e2020-01-01 14:08:48 +0530506 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400507 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000508 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400509 return err
510 }
511 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000512 log.Debugw("No-meter-has-been-installed-yet", log.Fields{"direction": Direction, "IntfID": sq.intfID, "OnuID": sq.onuID, "UniID": sq.uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400513 return nil
514 }
515 cir := KVStoreMeter.Bands[0].Rate
516 cbs := KVStoreMeter.Bands[0].BurstSize
517 eir := KVStoreMeter.Bands[1].Rate
518 ebs := KVStoreMeter.Bands[1].BurstSize
519 pir := cir + eir
520 pbs := cbs + ebs
521
522 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
523
Gamze Abakafee36392019-10-03 11:17:24 +0000524 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000525
526 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
527 if err != nil {
528 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
529 return err
530 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400531
npujarec5762e2020-01-01 14:08:48 +0530532 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000533 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
534 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400535 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000536 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400537 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400538 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000539 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530540 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000541 IntfId: sq.intfID, OnuId: sq.onuID,
542 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400543 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000544 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400545 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400546 }
547
salmansiddiqui7ac62132019-08-22 03:58:50 +0000548 log.Debug("Removed traffic schedulers successfully")
549
550 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400551 * delete the meter id on the KV store.
552 */
npujarec5762e2020-01-01 14:08:48 +0530553 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400554 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000555 log.Errorf("Failed to remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000556 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400557 }
558 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
559 return err
560}
561
Gamze Abakafee36392019-10-03 11:17:24 +0000562// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530563func (f *OpenOltFlowMgr) createTcontGemports(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uni string, uniPort uint32, TpID uint32, UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) (uint32, []uint32, *tp.TechProfile) {
Gamze Abakafee36392019-10-03 11:17:24 +0000564 var allocIDs []uint32
565 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530566 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530567 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000568 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000569
npujarec5762e2020-01-01 14:08:48 +0530570 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
571 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400572
573 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530574
575 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
576
Manikkaraj kb1d51442019-07-23 10:41:02 -0400577 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530578 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000579 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530580 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530581 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000582 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530583 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000584 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000585 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530586 }
npujarec5762e2020-01-01 14:08:48 +0530587 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530588 } else {
589 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530590 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530591 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400592 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000593 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
594 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530595 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400596 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000597 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400598 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530599 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400600 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000601 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
602 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530603 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400604 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000605 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400606 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530607 }
Gamze Abakafee36392019-10-03 11:17:24 +0000608
609 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000610 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000611 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400612 }
Gamze Abakafee36392019-10-03 11:17:24 +0000613
Girish Gowdra3d633032019-12-10 16:37:05 +0530614 if tpInstanceExists {
615 return allocID, gemPortIDs, techProfileInstance
616 }
617
618 allocIDs = appendUnique(allocIDs, allocID)
619 for _, gemPortID := range gemPortIDs {
620 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
621 }
622
Gamze Abakafee36392019-10-03 11:17:24 +0000623 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530624 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530625 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000626 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530627}
628
npujarec5762e2020-01-01 14:08:48 +0530629func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530630
631 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700632 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530633 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530634 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530635 log.Error("Errow while uploading allocID to KV store")
636 }
npujarec5762e2020-01-01 14:08:48 +0530637 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530638 log.Error("Errow while uploading GEMports to KV store")
639 }
npujarec5762e2020-01-01 14:08:48 +0530640 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530641 log.Error("Errow while uploading gemtopon map to KV store")
642 }
643 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400644 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530645 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400646 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530647}
648
649func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000650 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530651 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000652 for _, intfID := range techRange.IntfIds {
653 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400654 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000655 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530656 }
657 }
658 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400659 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800660 return NewErrInvalidValue(log.Fields{
661 "reason": "TP count does not match number of PON ports",
662 "tech-profile-count": tpCount,
663 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530664 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400665 log.Infow("Populated techprofile for ponports successfully",
666 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530667 return nil
668}
669
npujarec5762e2020-01-01 14:08:48 +0530670func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530671 portNo uint32, uplinkClassifier map[string]interface{},
672 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800673 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700674 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530675 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800676 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700677 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530678 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530679}
680
npujarec5762e2020-01-01 14:08:48 +0530681func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530682 portNo uint32, downlinkClassifier map[string]interface{},
683 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800684 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700685 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530686 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
687 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400688 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
689 if vlan, exists := downlinkClassifier[VlanVid]; exists {
690 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700691 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400692 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
693 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800694 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400695 }
696 }
697 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530698 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400699
Manikkaraj k884c1242019-04-11 16:26:42 +0530700 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700701 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400702 // vlan_vid is a uint32. must be type asserted as such or conversion fails
703 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530704 if ok {
705 downlinkAction[VlanVid] = dlClVid & 0xfff
706 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800707 return NewErrInvalidValue(log.Fields{
708 "reason": "failed to convert VLANID classifier",
709 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530710 }
711
David K. Bainbridge794735f2020-02-11 21:01:37 -0800712 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700713 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530714}
715
npujarec5762e2020-01-01 14:08:48 +0530716func (f *OpenOltFlowMgr) addHSIAFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Manikkaraj k884c1242019-04-11 16:26:42 +0530717 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800718 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530719 /* One of the OLT platform (Broadcom BAL) requires that symmetric
720 flows require the same flow_id to be used across UL and DL.
721 Since HSIA flow is the only symmetric flow currently, we need to
722 re-use the flow_id across both direction. The 'flow_category'
723 takes priority over flow_cookie to find any available HSIA_FLOW
724 id for the ONU.
725 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700726 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
727 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530728 "logicalFlow": *logicalFlow})
Gamze Abakafee36392019-10-03 11:17:24 +0000729 var vlanPbit uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400730 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000731 vlanPbit = classifier[VlanPcp].(uint32)
732 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800733 } else {
734 log.Debugw("bpit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400735 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700736 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530737 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800738 log.Debug("flow-already-exists")
739 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530740 }
npujarec5762e2020-01-01 14:08:48 +0530741 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530742 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800743 return NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530744 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800745 classifierProto, err := makeOpenOltClassifierField(classifier)
746 if err != nil {
747 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530748 }
749 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800750 actionProto, err := makeOpenOltActionField(action)
751 if err != nil {
752 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530753 }
754 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800755 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530756 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800757 return NewErrNotFound("nni-interface-id",
758 log.Fields{
759 "classifier": classifier,
760 "action": action,
761 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530762 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700763 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
764 OnuId: int32(onuID),
765 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000766 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530767 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700768 AllocId: int32(allocID),
769 NetworkIntfId: int32(networkIntfID),
770 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530771 Classifier: classifierProto,
772 Action: actionProto,
773 Priority: int32(logicalFlow.Priority),
774 Cookie: logicalFlow.Cookie,
775 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800776 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
777 return NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530778 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800779 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
780 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
781 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
782 flow.OnuId,
783 flow.UniId,
784 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
785 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
786 }
787 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530788}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000789
David K. Bainbridge794735f2020-02-11 21:01:37 -0800790func (f *OpenOltFlowMgr) addDHCPTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{}, action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530791
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530792 networkIntfID, err := getNniIntfID(classifier, action)
793 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800794 return NewErrNotFound("nni-interface-id", log.Fields{
795 "classifier": classifier,
796 "action": action},
797 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530798 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530799
800 // Clear the action map
801 for k := range action {
802 delete(action, k)
803 }
804
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700805 action[TrapToHost] = true
806 classifier[UDPSrc] = uint32(68)
807 classifier[UDPDst] = uint32(67)
808 classifier[PacketTagType] = SingleTag
809 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530810
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700811 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530812 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530813 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800814 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530815 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530816
David K. Bainbridge794735f2020-02-11 21:01:37 -0800817 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, DhcpFlow, 0 /*classifier[VLAN_PCP].(uint32)*/)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530818
819 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800820 return NewErrNotFound("flow", log.Fields{
821 "interface-id": intfID,
822 "gem-port": gemPortID,
823 "cookie": flowStoreCookie},
824 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530825 }
826
827 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
828
David K. Bainbridge794735f2020-02-11 21:01:37 -0800829 classifierProto, err := makeOpenOltClassifierField(classifier)
830 if err != nil {
831 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530832 }
833 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800834 actionProto, err := makeOpenOltActionField(action)
835 if err != nil {
836 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530837 }
838
David K. Bainbridge794735f2020-02-11 21:01:37 -0800839 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700840 OnuId: int32(onuID),
841 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530842 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700843 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700844 AllocId: int32(allocID),
845 NetworkIntfId: int32(networkIntfID),
846 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530847 Classifier: classifierProto,
848 Action: actionProto,
849 Priority: int32(logicalFlow.Priority),
850 Cookie: logicalFlow.Cookie,
851 PortNo: portNo}
852
David K. Bainbridge794735f2020-02-11 21:01:37 -0800853 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
854 return NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
855 }
856 log.Debug("DHCP UL flow added to device successfully")
857 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
858 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
859 dhcpFlow.OnuId,
860 dhcpFlow.UniId,
861 dhcpFlow.FlowId, flowsToKVStore); err != nil {
862 return NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530863 }
864
David K. Bainbridge794735f2020-02-11 21:01:37 -0800865 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530866}
867
Esin Karamanae41e2b2019-12-17 18:13:13 +0000868//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530869func (f *OpenOltFlowMgr) addIGMPTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -0800870 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
871 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000872}
873
874//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530875func (f *OpenOltFlowMgr) addUpstreamTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -0800876 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000877
878 networkIntfID, err := getNniIntfID(classifier, action)
879 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800880 return NewErrNotFound("nni-interface-id", log.Fields{
881 "classifier": classifier,
882 "action": action},
883 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000884 }
885
886 // Clear the action map
887 for k := range action {
888 delete(action, k)
889 }
890
891 action[TrapToHost] = true
892 classifier[PacketTagType] = SingleTag
893 delete(classifier, VlanVid)
894
895 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530896 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800897 log.Debug("Flow-exists-not-re-adding")
898 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000899 }
900
npujarec5762e2020-01-01 14:08:48 +0530901 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, flowType, 0, 0 /*classifier[VLAN_PCP].(uint32)*/)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000902
903 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800904 return NewErrNotFound("flow-id", log.Fields{
905 "interface-id": intfID,
906 "oni-id": onuID,
907 "cookie": flowStoreCookie,
908 "flow-type": flowType},
909 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000910 }
911
912 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
913
David K. Bainbridge794735f2020-02-11 21:01:37 -0800914 classifierProto, err := makeOpenOltClassifierField(classifier)
915 if err != nil {
916 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000917 }
918 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800919 actionProto, err := makeOpenOltActionField(action)
920 if err != nil {
921 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000922 }
923
David K. Bainbridge794735f2020-02-11 21:01:37 -0800924 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000925 OnuId: int32(onuID),
926 UniId: int32(uniID),
927 FlowId: flowID,
928 FlowType: Upstream,
929 AllocId: int32(allocID),
930 NetworkIntfId: int32(networkIntfID),
931 GemportId: int32(gemPortID),
932 Classifier: classifierProto,
933 Action: actionProto,
934 Priority: int32(logicalFlow.Priority),
935 Cookie: logicalFlow.Cookie,
936 PortNo: portNo}
937
David K. Bainbridge794735f2020-02-11 21:01:37 -0800938 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
939 return NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
940 }
941 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000942
David K. Bainbridge794735f2020-02-11 21:01:37 -0800943 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
944 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
945 flow.OnuId,
946 flow.UniId,
947 flow.FlowId, flowsToKVStore); err != nil {
948 return NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000949 }
950
David K. Bainbridge794735f2020-02-11 21:01:37 -0800951 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000952}
953
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700954// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
David K. Bainbridge794735f2020-02-11 21:01:37 -0800955func (f *OpenOltFlowMgr) addEAPOLFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, vlanID uint32, classifier map[string]interface{}, action map[string]interface{}) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700956 log.Debugw("Adding EAPOL to device", log.Fields{"intfId": intfID, "onuId": onuID, "portNo": portNo, "allocId": allocID, "gemPortId": gemPortID, "vlanId": vlanID, "flow": logicalFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +0530957
958 uplinkClassifier := make(map[string]interface{})
959 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530960
manikkaraj kbf256be2019-03-25 00:13:48 +0530961 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700962 uplinkClassifier[EthType] = uint32(EapEthType)
963 uplinkClassifier[PacketTagType] = SingleTag
964 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530965 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700966 uplinkAction[TrapToHost] = true
967 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530968 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800969 log.Debug("Flow-exists-not-re-adding")
970 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530971 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530972 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530973 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530974 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800975 return NewErrNotFound("flow-id", log.Fields{
976 "interface-id": intfID,
977 "onu-id": onuID,
978 "coookie": flowStoreCookie},
979 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530980 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700981 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530982
David K. Bainbridge794735f2020-02-11 21:01:37 -0800983 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
984 if err != nil {
985 return NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530986 }
987 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800988 actionProto, err := makeOpenOltActionField(uplinkAction)
989 if err != nil {
990 return NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530991 }
992 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800993 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530994 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800995 return NewErrNotFound("nni-interface-id", log.Fields{
996 "classifier": classifier,
997 "action": action},
998 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530999 }
1000
David K. Bainbridge794735f2020-02-11 21:01:37 -08001001 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001002 OnuId: int32(onuID),
1003 UniId: int32(uniID),
1004 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001005 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001006 AllocId: int32(allocID),
1007 NetworkIntfId: int32(networkIntfID),
1008 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301009 Classifier: classifierProto,
1010 Action: actionProto,
1011 Priority: int32(logicalFlow.Priority),
1012 Cookie: logicalFlow.Cookie,
1013 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001014 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
1015 return NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
1016 }
1017 log.Debug("EAPOL UL flow added to device successfully")
1018 flowCategory := "EAPOL"
1019 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1020 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1021 upstreamFlow.OnuId,
1022 upstreamFlow.UniId,
1023 upstreamFlow.FlowId,
1024 /* lowCategory, */
1025 flowsToKVStore); err != nil {
1026 return NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301027 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301028
manikkaraj kbf256be2019-03-25 00:13:48 +05301029 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001030 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301031}
1032
David K. Bainbridge794735f2020-02-11 21:01:37 -08001033func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001034 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001035
1036 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1037 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1038 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
1039 vid := vlanID & VlanvIDMask
1040 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001041 classifier.OVid = vid
1042 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301043 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001044 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1045 vid := uint32(metadata)
1046 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001047 classifier.IVid = vid
1048 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301049 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001050 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001051 if vlanPcp == 0 {
1052 classifier.OPbits = VlanPCPMask
1053 } else {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001054 classifier.OPbits = vlanPcp & VlanPCPMask
Manikkaraj kb1d51442019-07-23 10:41:02 -04001055 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301056 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001057 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1058 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1059 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1060 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001061 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001062 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1063 classifier.PktTagType = pktTagType
1064
1065 switch pktTagType {
1066 case SingleTag:
1067 case DoubleTag:
1068 case Untagged:
1069 default:
David K. Bainbridge794735f2020-02-11 21:01:37 -08001070 return nil, NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301071 }
1072 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001073 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301074}
1075
David K. Bainbridge794735f2020-02-11 21:01:37 -08001076func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001077 var actionCmd openoltpb2.ActionCmd
1078 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301079 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001080 if _, ok := actionInfo[PopVlan]; ok {
1081 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301082 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001083 } else if _, ok := actionInfo[PushVlan]; ok {
1084 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301085 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001086 } else if _, ok := actionInfo[TrapToHost]; ok {
1087 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301088 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001089 return nil, NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301090 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001091 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301092}
1093
Manikkaraj kb1d51442019-07-23 10:41:02 -04001094func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1095 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301096}
1097
Gamze Abakafee36392019-10-03 11:17:24 +00001098// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301099func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1100 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001101 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001102 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301103 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +00001104 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
Girish Gowdra54934262019-11-13 14:19:55 +05301105 // return err
1106 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001107 }
1108 }
1109 return nil
1110}
1111
1112// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301113func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001114 if uniPortName == "" {
1115 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1116 }
npujarec5762e2020-01-01 14:08:48 +05301117 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001118 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1119 return err
1120 }
1121 return nil
1122}
1123
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001124func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301125 if len(classifier) == 0 { // should never happen
1126 log.Error("Invalid classfier object")
1127 return 0
1128 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301129 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301130 var jsonData []byte
1131 var flowString string
1132 var err error
1133 // TODO: Do we need to marshall ??
1134 if jsonData, err = json.Marshal(classifier); err != nil {
1135 log.Error("Failed to encode classifier")
1136 return 0
1137 }
1138 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001139 if gemPortID != 0 {
1140 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301141 }
1142 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001143 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301144 hash := big.NewInt(0)
1145 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301146 generatedHash := hash.Uint64()
1147 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1148 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301149}
1150
npujarec5762e2020-01-01 14:08:48 +05301151func (f *OpenOltFlowMgr) getUpdatedFlowInfo(ctx context.Context, flow *openoltpb2.Flow, flowStoreCookie uint64, flowCategory string, deviceFlowID uint32, logicalFlowID uint64) *[]rsrcMgr.FlowInfo {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301152 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001153 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001154 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1155 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1156 */
1157 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001158 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001159 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001160 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001161 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001162 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301163 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001164 if existingFlows != nil {
1165 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001166 //for _, f := range *existingFlows {
1167 // flows = append(flows, f)
1168 //}
1169 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001170 }
1171 log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
manikkaraj kbf256be2019-03-25 00:13:48 +05301172 return &flows
1173}
1174
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001175//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1176// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1177// var intfId uint32
1178// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1179// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1180// */
1181// if flow.AccessIntfId != -1 {
1182// intfId = uint32(flow.AccessIntfId)
1183// } else {
1184// intfId = uint32(flow.NetworkIntfId)
1185// }
1186// // Get existing flows matching flowid for given subscriber from KV store
1187// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1188// if existingFlows != nil {
1189// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1190// for _, f := range *existingFlows {
1191// flows = append(flows, f)
1192// }
1193// }
1194// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1195// return &flows
1196//}
1197
npujarec5762e2020-01-01 14:08:48 +05301198func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(ctx context.Context, intfID int32, onuID int32, uniID int32, flowID uint32, flows *[]rsrcMgr.FlowInfo) error {
manikkaraj k17652a72019-05-06 09:06:36 -04001199 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301200 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001201 log.Debug("Error while Storing flow into KV store")
1202 return err
1203 }
1204 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301205 return nil
1206}
1207
David K. Bainbridge794735f2020-02-11 21:01:37 -08001208func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001209
1210 var intfID uint32
1211 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1212 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1213 */
1214 if deviceFlow.AccessIntfId != -1 {
1215 intfID = uint32(deviceFlow.AccessIntfId)
1216 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001217 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001218 intfID = uint32(deviceFlow.NetworkIntfId)
1219 }
1220
manikkaraj kbf256be2019-03-25 00:13:48 +05301221 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1222 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001223
1224 st, _ := status.FromError(err)
1225 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001226 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001227 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301228 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001229
1230 if err != nil {
1231 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301232 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001233 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001234 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301235 if deviceFlow.GemportId != -1 {
1236 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301237 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301238 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301239 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001240 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001241}
1242
David K. Bainbridge794735f2020-02-11 21:01:37 -08001243func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001244 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1245 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1246 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001247 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1248 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1249 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001250 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001251 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001252 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001253 return err
serkant.uluderya245caba2019-09-24 23:15:29 -07001254
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001255 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001256 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001257 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301258}
1259
1260/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1261 //update core flows_proxy : flows_proxy.update('/', flows)
1262}
1263
1264func generateStoredId(flowId uint32, direction string)uint32{
1265
David K. Bainbridge82efc492019-09-04 09:57:11 -07001266 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301267 log.Debug("Upstream flow shifting flowid")
1268 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001269 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301270 log.Debug("Downstream flow not shifting flowid")
1271 return flowId
1272 }else{
1273 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1274 return flowId
1275 }
1276}
1277
1278*/
1279
David K. Bainbridge794735f2020-02-11 21:01:37 -08001280func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001281
1282 classifierInfo := make(map[string]interface{})
1283 actionInfo := make(map[string]interface{})
1284
1285 classifierInfo[EthType] = uint32(LldpEthType)
1286 classifierInfo[PacketTagType] = Untagged
1287 actionInfo[TrapToHost] = true
1288
1289 // LLDP flow is installed to trap LLDP packets on the NNI port.
1290 // We manage flow_id resource pool on per PON port basis.
1291 // Since this situation is tricky, as a hack, we pass the NNI port
1292 // index (network_intf_id) as PON port Index for the flow_id resource
1293 // pool. Also, there is no ONU Id available for trapping LLDP packets
1294 // on NNI port, use onu_id as -1 (invalid)
1295 // ****************** CAVEAT *******************
1296 // This logic works if the NNI Port Id falls within the same valid
1297 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1298 // we need to have a re-look at this.
1299 // *********************************************
1300
1301 var onuID = -1
1302 var uniID = -1
1303 var gemPortID = -1
1304
David K. Bainbridge794735f2020-02-11 21:01:37 -08001305 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1306 if err != nil {
1307 return NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
1308 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001309 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301310 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001311 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001312 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001313 }
npujarec5762e2020-01-01 14:08:48 +05301314 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001315
1316 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001317 return NewErrNotFound("flow-id", log.Fields{
1318 "interface-id": networkInterfaceID,
1319 "onu-id": onuID,
1320 "uni-id": uniID,
1321 "gem-port-id": gemPortID,
1322 "cookie": flowStoreCookie},
1323 err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001324 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001325 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1326 if err != nil {
1327 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001328 }
1329 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001330 actionProto, err := makeOpenOltActionField(actionInfo)
1331 if err != nil {
1332 return NewErrInvalidValue(log.Fields{"action": actionInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001333 }
1334 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1335
1336 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1337 OnuId: int32(onuID), // OnuId not required
1338 UniId: int32(uniID), // UniId not used
1339 FlowId: flowID,
1340 FlowType: Downstream,
1341 NetworkIntfId: int32(networkInterfaceID),
1342 GemportId: int32(gemPortID),
1343 Classifier: classifierProto,
1344 Action: actionProto,
1345 Priority: int32(flow.Priority),
1346 Cookie: flow.Cookie,
1347 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001348 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
1349 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001350 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001351 log.Debug("LLDP trap on NNI flow added to device successfully")
1352 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1353 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1354 int32(onuID),
1355 int32(uniID),
1356 flowID, flowsToKVStore); err != nil {
1357 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
1358 }
1359 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301360}
1361
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301362func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001363 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1364}
1365
1366//getOnuChildDevice to fetch onu
1367func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1368 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1369 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001370 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1371 if err != nil {
1372 return nil, NewErrNotFound("onu", log.Fields{
1373 "interface-id": parentPortNo,
1374 "onu-id": onuID},
1375 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301376 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301377 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1378 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301379}
1380
1381func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001382 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301383 return nil
1384}
1385
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001386func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1387 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301388}
1389
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001390func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001391 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001392 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001393 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001394 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001395}
1396
Girish Gowdra6b130582019-11-20 16:45:20 +05301397func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1398 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1399 if err != nil {
1400 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1401 return err
1402 }
1403
1404 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1405 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1406 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1407 delGemPortMsg,
1408 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1409 f.deviceHandler.deviceType,
1410 onuDevice.Type,
1411 onuDevice.Id,
1412 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1413 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1414 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1415 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1416 return sendErr
1417 }
1418 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1419 return nil
1420}
1421
1422func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1423 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1424 if err != nil {
1425 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1426 return err
1427 }
1428
1429 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1430 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1431 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1432 delTcontMsg,
1433 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1434 f.deviceHandler.deviceType,
1435 onuDevice.Type,
1436 onuDevice.Id,
1437 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1438 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1439 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1440 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1441 return sendErr
1442 }
1443 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1444 return nil
1445}
1446
Girish Gowdra3d633032019-12-10 16:37:05 +05301447func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1448 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1449 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1450 if val.(int) > 0 {
1451 pnFlDels := val.(int) - 1
1452 if pnFlDels > 0 {
1453 log.Debugw("flow delete succeeded, more pending",
1454 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1455 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1456 } else {
1457 log.Debugw("all pending flow deletes handled, removing entry from map",
1458 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1459 f.pendingFlowDelete.Delete(pnFlDelKey)
1460 }
1461 }
1462 } else {
1463 log.Debugw("no pending delete flows found",
1464 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1465
1466 }
1467
1468}
1469
Girish Gowdrac3037402020-01-22 20:29:53 +05301470// Once the gemport is released for a given onu, it also has to be cleared from local cache
1471// which was used for deriving the gemport->logicalPortNo during packet-in.
1472// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1473// is conveyed to ONOS during packet-in OF message.
1474func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1475 f.lockCache.Lock()
1476 defer f.lockCache.Unlock()
1477 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001478 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301479 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001480 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301481 // If the gemport is found, delete it from local cache.
1482 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001483 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1484 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301485 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001486 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301487 break
1488 }
1489 }
1490 break
1491 }
1492 }
1493}
1494
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301495//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301496func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301497 gemPortID int32, flowID uint32, flowDirection string,
1498 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001499
Chaitrashree G S90a17952019-11-14 21:51:21 -05001500 tpID, err := getTpIDFromFlow(flow)
1501 if err != nil {
1502 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1503 return err
1504 }
Gamze Abakafee36392019-10-03 11:17:24 +00001505
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001506 if len(updatedFlows) >= 0 {
1507 // There are still flows referencing the same flow_id.
1508 // So the flow should not be freed yet.
1509 // For ex: Case of HSIA where same flow is shared
1510 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301511 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001512 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301513 // Do this for subscriber flows only (not trap from NNI flows)
1514 if onuID != -1 && uniID != -1 {
1515 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1516 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1517 log.Debugw("creating entry for pending flow delete",
1518 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1519 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1520 } else {
1521 pnFlDels := val.(int) + 1
1522 log.Debugw("updating flow delete entry",
1523 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1524 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1525 }
1526
1527 defer f.deletePendingFlows(Intf, onuID, uniID)
1528 }
1529
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301530 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301531 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001532
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301533 uni := getUniPortPath(Intf, onuID, uniID)
1534 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001535 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301536 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001537 if err != nil { // This should not happen, something wrong in KV backend transaction
1538 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301539 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001540 }
1541 if techprofileInst == nil {
1542 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301543 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001544 }
1545
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301546 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001547 if f.isGemPortUsedByAnotherFlow(gemPK) {
1548 flowIDs := f.flowsUsedByGemPort[gemPK]
1549 for i, flowIDinMap := range flowIDs {
1550 if flowIDinMap == flowID {
1551 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301552 // everytime flowsUsedByGemPort cache is updated the same should be updated
1553 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001554 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301555 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001556 break
1557 }
1558 }
1559 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301560 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001561 }
Gamze Abakafee36392019-10-03 11:17:24 +00001562 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301563 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001564 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1565 // But it is anyway eventually removed later when the TechProfile is freed, so not a big issue for now.
npujarec5762e2020-01-01 14:08:48 +05301566 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301567 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001568 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301569 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1570 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001571 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301572 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1573 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001574 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301575 // Delete the gem port on the ONU.
1576 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1577 log.Errorw("error processing delete gem-port towards onu",
1578 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1579 }
Gamze Abakafee36392019-10-03 11:17:24 +00001580
npujarec5762e2020-01-01 14:08:48 +05301581 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001582 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301583 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1584 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1585 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1586 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1587 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301588 // Delete the TCONT on the ONU.
1589 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1590 log.Errorw("error processing delete tcont towards onu",
1591 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1592 }
Gamze Abakafee36392019-10-03 11:17:24 +00001593 }
1594 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001595 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301596 return nil
1597}
1598
David K. Bainbridge794735f2020-02-11 21:01:37 -08001599// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301600func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301601
1602 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001603
1604 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301605 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001606 return
1607 }
1608
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301609 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301610 classifierInfo := make(map[string]interface{})
1611
1612 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1613 if err != nil {
1614 log.Error(err)
1615 return
1616 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301617
David K. Bainbridge794735f2020-02-11 21:01:37 -08001618 onuID := int32(onu)
1619 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301620
1621 for _, field := range flows.GetOfbFields(flow) {
1622 if field.Type == flows.IP_PROTO {
1623 classifierInfo[IPProto] = field.GetIpProto()
1624 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1625 }
1626 }
1627 log.Debugw("Extracted access info from flow to be deleted",
1628 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1629
1630 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1631 onuID = -1
1632 uniID = -1
1633 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001634 Intf, err = IntfIDFromNniPortNum(inPort)
1635 if err != nil {
1636 log.Errorw("invalid-in-port-number",
1637 log.Fields{
1638 "port-number": inPort,
1639 "error": err})
1640 return
1641 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301642 }
npujarec5762e2020-01-01 14:08:48 +05301643 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001644 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301645 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301646 if flowInfo == nil {
1647 log.Debugw("No FlowInfo found found in KV store",
1648 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1649 return
1650 }
1651 updatedFlows = nil
1652 for _, flow := range *flowInfo {
1653 updatedFlows = append(updatedFlows, flow)
1654 }
1655
1656 for i, storedFlow := range updatedFlows {
1657 if flow.Id == storedFlow.LogicalFlowID {
1658 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1659 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001660 // DKB
1661 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1662 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1663 return
1664 }
1665 log.Debug("Flow removed from device successfully")
1666 //Remove the Flow from FlowInfo
1667 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1668 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1669 flowID, flowDirection, portNum, updatedFlows); err != nil {
1670 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301671 return
1672 }
1673 }
1674 }
1675 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001676}
1677
Esin Karamanccb714b2019-11-29 15:02:06 +00001678//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1679// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301680func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001681 classifierInfo := make(map[string]interface{})
1682 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301683 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001684
1685 if err != nil {
1686 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1687 return
1688 }
1689
David K. Bainbridge794735f2020-02-11 21:01:37 -08001690 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1691 if err != nil {
1692 // DKB
1693 log.Errorw("invalid-in-port-number",
1694 log.Fields{
1695 "port-number": inPort,
1696 "error": err})
1697 return
1698 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001699 var onuID = int32(NoneOnuID)
1700 var uniID = int32(NoneUniID)
1701 var flowID uint32
1702 var updatedFlows []rsrcMgr.FlowInfo
1703
npujarec5762e2020-01-01 14:08:48 +05301704 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001705
1706 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301707 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001708 if flowInfo == nil {
1709 log.Debugw("No multicast FlowInfo found in the KV store",
1710 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1711 continue
1712 }
1713 updatedFlows = nil
1714 for _, flow := range *flowInfo {
1715 updatedFlows = append(updatedFlows, flow)
1716 }
1717 for i, storedFlow := range updatedFlows {
1718 if flow.Id == storedFlow.LogicalFlowID {
1719 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1720 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1721 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001722 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1723 // DKB
1724 log.Errorw("failed-to-remove-multicast-flow",
1725 log.Fields{
1726 "flow-id": flow.Id,
1727 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001728 return
1729 }
1730 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1731 //Remove the Flow from FlowInfo
1732 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301733 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001734 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1735 return
1736 }
1737 //release flow id
1738 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301739 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001740 }
1741 }
1742 }
1743}
1744
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001745//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301746func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001747 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301748 var direction string
1749 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001750
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301751 for _, action := range flows.GetActions(flow) {
1752 if action.Type == flows.OUTPUT {
1753 if out := action.GetOutput(); out != nil {
1754 actionInfo[Output] = out.GetPort()
1755 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1756 } else {
1757 log.Error("Invalid output port in action")
1758 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001759 }
1760 }
1761 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001762
1763 if flows.HasGroup(flow) {
1764 direction = Multicast
1765 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301766 direction = Upstream
1767 } else {
1768 direction = Downstream
1769 }
npujarec5762e2020-01-01 14:08:48 +05301770 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301771
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001772 return
1773}
1774
Girish Gowdra3d633032019-12-10 16:37:05 +05301775func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1776 uniID uint32, ch chan bool) {
1777 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1778 for {
1779 select {
1780 case <-time.After(20 * time.Millisecond):
1781 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1782 log.Debug("pending flow deletes completed")
1783 ch <- true
1784 return
1785 }
1786 case <-ctx.Done():
1787 log.Error("flow delete wait handler routine canceled")
1788 return
1789 }
1790 }
1791}
1792
Esin Karamanae41e2b2019-12-17 18:13:13 +00001793//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1794func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1795 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1796 if ethType, ok := classifierInfo[EthType]; ok {
1797 if ethType.(uint32) == IPv4EthType {
1798 if ipProto, ok := classifierInfo[IPProto]; ok {
1799 if ipProto.(uint32) == IgmpProto {
1800 return true
1801 }
1802 }
1803 }
1804 }
1805 }
1806 return false
1807}
1808
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001809// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301810// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301811func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001812 classifierInfo := make(map[string]interface{})
1813 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001814 var UsMeterID uint32
1815 var DsMeterID uint32
1816
1817 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001818 formulateClassifierInfoFromFlow(classifierInfo, flow)
1819
1820 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1821 if err != nil {
1822 // Error logging is already done in the called function
1823 // So just return in case of error
1824 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301825 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001826
Esin Karamanccb714b2019-11-29 15:02:06 +00001827 if flows.HasGroup(flow) {
1828 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301829 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001830 return
1831 }
1832
manikkaraj k17652a72019-05-06 09:06:36 -04001833 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001834 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1835 if err != nil {
1836 // error if any, already logged in the called function
1837 return
manikkaraj k17652a72019-05-06 09:06:36 -04001838 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001839
David K. Bainbridge82efc492019-09-04 09:57:11 -07001840 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1841 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001842
Humera Kouser94d7a842019-08-25 19:04:32 -04001843 if ethType, ok := classifierInfo[EthType]; ok {
1844 if ethType.(uint32) == LldpEthType {
1845 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301846 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001847 return
1848 }
1849 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001850 if ipProto, ok := classifierInfo[IPProto]; ok {
1851 if ipProto.(uint32) == IPProtoDhcp {
1852 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301853 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001854 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301855 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001856 return
1857 }
1858 }
1859 }
1860 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001861 if isIgmpTrapDownstreamFlow(classifierInfo) {
1862 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301863 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001864 return
1865 }
A R Karthick1f85b802019-10-11 05:06:05 +00001866
1867 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301868 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001869
Chaitrashree G S90a17952019-11-14 21:51:21 -05001870 TpID, err := getTpIDFromFlow(flow)
1871 if err != nil {
1872 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1873 return
1874 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001875 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001876 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001877 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001878 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1879 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001880 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001881 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1882
1883 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301884
1885 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1886 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1887 log.Debugw("no pending flows found, going ahead with flow install", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301888 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301889 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301890 pendingFlowDelComplete := make(chan bool)
1891 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1892 select {
1893 case <-pendingFlowDelComplete:
1894 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301895 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301896
1897 case <-time.After(10 * time.Second):
1898 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1899 }
1900 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001901}
1902
Esin Karamanccb714b2019-11-29 15:02:06 +00001903// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001904func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001905 classifierInfo[PacketTagType] = DoubleTag
1906 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1907
npujarec5762e2020-01-01 14:08:48 +05301908 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001909 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001910 return NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001911 }
1912 //replace ipDst with ethDst
1913 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1914 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1915 // replace ipv4_dst classifier with eth_dst
1916 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1917 delete(classifierInfo, Ipv4Dst)
1918 delete(classifierInfo, EthType)
1919 classifierInfo[EthDst] = multicastMac
1920 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1921 }
1922
David K. Bainbridge794735f2020-02-11 21:01:37 -08001923 onuID := NoneOnuID
1924 uniID := NoneUniID
1925 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001926
David K. Bainbridge794735f2020-02-11 21:01:37 -08001927 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1928 if err != nil {
1929 return NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
1930 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001931
David K. Bainbridge794735f2020-02-11 21:01:37 -08001932 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301933 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001934 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1935 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001936 }
npujarec5762e2020-01-01 14:08:48 +05301937 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001938 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001939 return NewErrNotFound("multicast-flow-id", log.Fields{
1940 "interface-id": networkInterfaceID,
1941 "onu-id": onuID,
1942 "uni-id": uniID,
1943 "gem-port-id": gemPortID,
1944 "cookie": flowStoreCookie},
1945 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001946 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001947 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1948 if err != nil {
1949 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001950 }
1951 groupID := actionInfo[GroupID].(uint32)
1952 multicastFlow := openoltpb2.Flow{
1953 FlowId: flowID,
1954 FlowType: Multicast,
1955 NetworkIntfId: int32(networkInterfaceID),
1956 GroupId: groupID,
1957 Classifier: classifierProto,
1958 Priority: int32(flow.Priority),
1959 Cookie: flow.Cookie}
1960
David K. Bainbridge794735f2020-02-11 21:01:37 -08001961 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
1962 return NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1963 }
1964 log.Debug("multicast flow added to device successfully")
1965 //get cached group
1966 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1967 if err == nil {
1968 //calling groupAdd to set group members after multicast flow creation
1969 if f.ModifyGroup(ctx, group) {
1970 //cached group can be removed now
1971 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001972 }
1973 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001974
1975 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1976 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1977 int32(onuID),
1978 int32(uniID),
1979 flowID, flowsToKVStore); err != nil {
1980 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1981 }
1982 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001983}
1984
1985//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301986func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001987 if _, ok := classifierInfo[InPort]; ok {
1988 return classifierInfo[InPort].(uint32), nil
1989 }
1990 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301991 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001992 if e == nil && len(nniPorts) > 0 {
1993 return nniPorts[0], nil
1994 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001995 return 0, NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001996}
1997
1998// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05301999func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00002000 log.Infow("add-group", log.Fields{"group": group})
2001 if group == nil {
2002 log.Warn("skipping nil group")
2003 return
2004 }
2005
2006 groupToOlt := openoltpb2.Group{
2007 GroupId: group.Desc.GroupId,
2008 Command: openoltpb2.Group_SET_MEMBERS,
2009 Action: f.buildGroupAction(),
2010 }
2011
2012 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302013 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002014 if err != nil {
2015 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
2016 return
2017 }
2018 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302019 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002020 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
2021 } else {
2022 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2023 }
2024}
2025
2026//buildGroupAction creates and returns a group action
2027func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2028 var actionCmd openoltpb2.ActionCmd
2029 var action openoltpb2.Action
2030 action.Cmd = &actionCmd
2031 //pop outer vlan
2032 action.Cmd.RemoveOuterTag = true
2033 return &action
2034}
2035
2036// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05302037func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00002038 log.Infow("modify-group", log.Fields{"group": group})
2039 if group == nil || group.Desc == nil {
2040 log.Warn("cannot modify group; group is nil")
2041 return false
2042 }
2043
2044 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2045 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302046 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002047
2048 if err != nil {
2049 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2050 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2051 return false
2052 }
2053
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002054 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002055 if groupExists {
2056 // group already exists
2057 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002058 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002059 } else {
2060 current = f.buildGroup(group.Desc.GroupId, nil)
2061 }
2062
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002063 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2064 // get members to be added
2065 membersToBeAdded := f.findDiff(current, new)
2066 // get members to be removed
2067 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002068
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002069 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2070 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002071
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002072 groupToOlt := openoltpb2.Group{
2073 GroupId: group.Desc.GroupId,
2074 }
2075 var added, removed = true, true
2076 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2077 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2078 groupToOlt.Members = membersToBeAdded
2079 //execute addMembers
2080 added = f.callGroupAddRemove(&groupToOlt)
2081 }
2082 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2083 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2084 groupToOlt.Members = membersToBeRemoved
2085 //execute removeMembers
2086 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002087 }
2088
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002089 //save the modified group
2090 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302091 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002092 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2093 }
2094 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002095 } else {
2096 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2097 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002098 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002099 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002100}
2101
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002102//callGroupAddRemove performs add/remove buckets operation for the indicated group
2103func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2104 if err := f.performGroupOperation(group); err != nil {
2105 st, _ := status.FromError(err)
2106 //ignore already exists error code
2107 if st.Code() != codes.AlreadyExists {
2108 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002109 }
2110 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002111 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002112}
2113
2114//findDiff compares group members and finds members which only exists in groups2
2115func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2116 var members []*openoltpb2.GroupMember
2117 for _, bucket := range group2.Members {
2118 if !f.contains(group1.Members, bucket) {
2119 // bucket does not exist and must be added
2120 members = append(members, bucket)
2121 }
2122 }
2123 return members
2124}
2125
2126//contains returns true if the members list contains the given member; false otherwise
2127func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2128 for _, groupMember := range members {
2129 if groupMember.InterfaceId == member.InterfaceId {
2130 return true
2131 }
2132 }
2133 return false
2134}
2135
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002136//performGroupOperation call performGroupOperation operation of openolt proto
2137func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002138 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2139 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2140 if err != nil {
2141 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2142 }
2143 return err
2144}
2145
2146//buildGroup build openoltpb2.Group from given group id and bucket list
2147func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2148 group := openoltpb2.Group{
2149 GroupId: groupID}
2150 // create members of the group
2151 if buckets != nil {
2152 for _, ofBucket := range buckets {
2153 member := f.buildMember(ofBucket)
2154 if member != nil && !f.contains(group.Members, member) {
2155 group.Members = append(group.Members, member)
2156 }
2157 }
2158 }
2159 return &group
2160}
2161
2162//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2163func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2164 var outPort uint32
2165 outPortFound := false
2166 for _, ofAction := range ofBucket.Actions {
2167 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2168 outPort = ofAction.GetOutput().Port
2169 outPortFound = true
2170 }
2171 }
2172
2173 if !outPortFound {
2174 log.Debugw("bucket skipped since no out port found in it",
2175 log.Fields{"ofBucket": ofBucket})
2176 return nil
2177 }
2178 interfaceID := IntfIDFromUniPortNum(outPort)
2179 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2180 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2181 member := openoltpb2.GroupMember{
2182 InterfaceId: interfaceID,
2183 InterfaceType: openoltpb2.GroupMember_PON,
2184 GemPortId: groupInfo.gemPortID,
2185 Priority: groupInfo.servicePriority,
2186 }
2187 //add member to the group
2188 return &member
2189 }
2190 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2191 log.Fields{"ofBucket": ofBucket})
2192 return nil
2193}
2194
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002195//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002196func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002197
2198 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302199 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002200 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302201 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302202 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302203 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002204
Manikkaraj kb1d51442019-07-23 10:41:02 -04002205 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002206 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002207 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2208 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2209 tpDownloadMsg,
2210 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2211 f.deviceHandler.deviceType,
2212 onuDevice.Type,
2213 onuDevice.Id,
2214 onuDevice.ProxyAddress.DeviceId, "")
2215 if sendErr != nil {
2216 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2217 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2218 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2219 return sendErr
2220 }
2221 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302222 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302223}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002224
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302225//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302226func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302227
2228 f.lockCache.Lock()
2229 defer f.lockCache.Unlock()
2230 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2231 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
npujarec5762e2020-01-01 14:08:48 +05302232 if err := f.resourceMgr.AddOnuInfo(ctx, intfID, onu); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302233 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2234 return
2235 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002236 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2237}
2238
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302239//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302240func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302241 f.lockCache.Lock()
2242 defer f.lockCache.Unlock()
2243 onugem := f.onuGemInfo[intfID]
2244 // update the gem to the local cache as well as to kv strore
2245 for idx, onu := range onugem {
2246 if onu.OnuID == onuID {
2247 // check if gem already exists , else update the cache and kvstore
2248 for _, gem := range onu.GemPorts {
2249 if gem == gemPort {
2250 log.Debugw("Gem already in cache, no need to update cache and kv store",
2251 log.Fields{"gem": gemPort})
2252 return
2253 }
2254 }
2255 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2256 f.onuGemInfo[intfID] = onugem
2257 }
2258 }
npujarec5762e2020-01-01 14:08:48 +05302259 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302260 if err != nil {
2261 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002262 return
2263 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002264}
2265
2266// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002267
2268//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2269func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302270
2271 f.lockCache.Lock()
2272 defer f.lockCache.Unlock()
2273
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002274 log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPortId": gemPortID})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302275 // get onuid from the onugem info cache
2276 onugem := f.onuGemInfo[intfID]
2277 for _, onu := range onugem {
2278 for _, gem := range onu.GemPorts {
2279 if gem == gemPortID {
2280 return onu.OnuID, nil
2281 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002282 }
2283 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002284 return uint32(0), NewErrNotFound("onu-id", log.Fields{
2285 "serial-number": serialNumber,
2286 "interface-id": intfID,
2287 "gem-port-id": gemPortID},
2288 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002289}
2290
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002291//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302292func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002293 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002294 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002295 var err error
2296
2297 if packetIn.IntfType == "pon" {
2298 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002299 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002300 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2301 return logicalPortNum, err
2302 }
2303 if packetIn.PortNo != 0 {
2304 logicalPortNum = packetIn.PortNo
2305 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002306 uniID := uint32(0) // FIXME - multi-uni support
2307 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002308 }
2309 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302310 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002311 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002312 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002313 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002314 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2315 "logicalPortNum": logicalPortNum,
2316 "IntfType": packetIn.IntfType,
2317 "packet": hex.EncodeToString(packetIn.Pkt),
2318 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002319 return logicalPortNum, nil
2320}
2321
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002322//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302323func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002324 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002325 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302326
2327 f.lockCache.Lock()
2328 defer f.lockCache.Unlock()
2329 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2330
2331 gemPortID, ok := f.packetInGemPort[pktInkey]
2332 if ok {
2333 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2334 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002335 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302336 //If gem is not found in cache try to get it from kv store, if found in kv store, update the cache and return.
npujarec5762e2020-01-01 14:08:48 +05302337 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302338 if err == nil {
2339 if gemPortID != 0 {
2340 f.packetInGemPort[pktInkey] = gemPortID
2341 log.Debugw("Found gem port from kv store and updating cache with gemport",
2342 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2343 return gemPortID, nil
2344 }
2345 }
2346 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2347 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002348}
2349
npujarec5762e2020-01-01 14:08:48 +05302350func installFlowOnAllGemports(ctx context.Context,
2351 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002352 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002353 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302354 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302355 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
David K. Bainbridge794735f2020-02-11 21:01:37 -08002356 classifier map[string]interface{}, action map[string]interface{}) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002357 args map[string]uint32,
2358 classifier map[string]interface{}, action map[string]interface{},
2359 logicalFlow *ofp.OfpFlowStats,
2360 gemPorts []uint32,
2361 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002362 vlanID ...uint32) {
2363 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
2364 for _, gemPortID := range gemPorts {
Manikkaraj kb1d51442019-07-23 10:41:02 -04002365 if FlowType == HsiaFlow || FlowType == DhcpFlow {
npujarec5762e2020-01-01 14:08:48 +05302366 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002367 } else if FlowType == EapolFlow {
npujarec5762e2020-01-01 14:08:48 +05302368 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], logicalFlow, args["allocId"], gemPortID, vlanID[0], classifier, action)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002369 } else {
2370 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2371 return
2372 }
2373 }
2374}
2375
David K. Bainbridge794735f2020-02-11 21:01:37 -08002376func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002377 log.Debug("Adding trap-dhcp-of-nni-flow")
2378 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002379 classifier[PacketTagType] = DoubleTag
2380 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002381 /* We manage flowId resource pool on per PON port basis.
2382 Since this situation is tricky, as a hack, we pass the NNI port
2383 index (network_intf_id) as PON port Index for the flowId resource
2384 pool. Also, there is no ONU Id available for trapping DHCP packets
2385 on NNI port, use onu_id as -1 (invalid)
2386 ****************** CAVEAT *******************
2387 This logic works if the NNI Port Id falls within the same valid
2388 range of PON Port Ids. If this doesn't work for some OLT Vendor
2389 we need to have a re-look at this.
2390 *********************************************
2391 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002392 onuID := -1
2393 uniID := -1
2394 gemPortID := -1
2395 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002396 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302397 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002398 return NewErrNotFound("nni-intreface-id", log.Fields{
2399 "classifier": classifier,
2400 "action": action},
2401 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302402 }
2403
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002404 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302405 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002406 log.Debug("Flow-exists-not-re-adding")
2407 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002408 }
npujarec5762e2020-01-01 14:08:48 +05302409 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002410 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002411 return NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
2412 "interface-id": networkInterfaceID,
2413 "onu-id": onuID,
2414 "uni-id": uniID,
2415 "gem-port-id": gemPortID,
2416 "cookie": flowStoreCookie},
2417 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002418 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002419 classifierProto, err := makeOpenOltClassifierField(classifier)
2420 if err != nil {
2421 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002422 }
2423 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002424 actionProto, err := makeOpenOltActionField(action)
2425 if err != nil {
2426 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002427 }
2428 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002429 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2430 OnuId: int32(onuID), // OnuId not required
2431 UniId: int32(uniID), // UniId not used
2432 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002433 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002434 AllocId: int32(allocID), // AllocId not used
2435 NetworkIntfId: int32(networkInterfaceID),
2436 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002437 Classifier: classifierProto,
2438 Action: actionProto,
2439 Priority: int32(logicalFlow.Priority),
2440 Cookie: logicalFlow.Cookie,
2441 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002442 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2443 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002444 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002445 log.Debug("DHCP trap on NNI flow added to device successfully")
2446 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2447 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2448 int32(onuID),
2449 int32(uniID),
2450 flowID, flowsToKVStore); err != nil {
2451 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2452 }
2453 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002454}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002455
Esin Karamanae41e2b2019-12-17 18:13:13 +00002456//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2457func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2458 var packetType string
2459 ovid, ivid := false, false
2460 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2461 vid := vlanID & VlanvIDMask
2462 if vid != ReservedVlan {
2463 ovid = true
2464 }
2465 }
2466 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2467 vid := uint32(metadata)
2468 if vid != ReservedVlan {
2469 ivid = true
2470 }
2471 }
2472 if ovid && ivid {
2473 packetType = DoubleTag
2474 } else if !ovid && !ivid {
2475 packetType = Untagged
2476 } else {
2477 packetType = SingleTag
2478 }
2479 return packetType
2480}
2481
2482//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002483func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002484 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2485 action := make(map[string]interface{})
2486 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2487 action[TrapToHost] = true
2488 /* We manage flowId resource pool on per PON port basis.
2489 Since this situation is tricky, as a hack, we pass the NNI port
2490 index (network_intf_id) as PON port Index for the flowId resource
2491 pool. Also, there is no ONU Id available for trapping packets
2492 on NNI port, use onu_id as -1 (invalid)
2493 ****************** CAVEAT *******************
2494 This logic works if the NNI Port Id falls within the same valid
2495 range of PON Port Ids. If this doesn't work for some OLT Vendor
2496 we need to have a re-look at this.
2497 *********************************************
2498 */
2499 onuID := -1
2500 uniID := -1
2501 gemPortID := -1
2502 allocID := -1
2503 networkInterfaceID, err := getNniIntfID(classifier, action)
2504 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002505 return NewErrNotFound("nni-interface-id", log.Fields{
2506 "classifier": classifier,
2507 "action": action},
2508 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002509 }
2510 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302511 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002512 log.Debug("igmp-flow-exists-not-re-adding")
2513 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002514 }
npujarec5762e2020-01-01 14:08:48 +05302515 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002516 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002517 return NewErrNotFound("igmp-flow-id", log.Fields{
2518 "interface-id": networkInterfaceID,
2519 "onu-id": onuID,
2520 "uni-id": uniID,
2521 "gem-port-id": gemPortID,
2522 "cookie": flowStoreCookie},
2523 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002524 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002525 classifierProto, err := makeOpenOltClassifierField(classifier)
2526 if err != nil {
2527 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002528 }
2529 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002530 actionProto, err := makeOpenOltActionField(action)
2531 if err != nil {
2532 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002533 }
2534 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2535 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2536 OnuId: int32(onuID), // OnuId not required
2537 UniId: int32(uniID), // UniId not used
2538 FlowId: flowID,
2539 FlowType: Downstream,
2540 AllocId: int32(allocID), // AllocId not used
2541 NetworkIntfId: int32(networkInterfaceID),
2542 GemportId: int32(gemPortID), // GemportId not used
2543 Classifier: classifierProto,
2544 Action: actionProto,
2545 Priority: int32(logicalFlow.Priority),
2546 Cookie: logicalFlow.Cookie,
2547 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002548 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2549 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002550 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002551 log.Debug("IGMP Trap on NNI flow added to device successfully")
2552 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2553 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2554 int32(onuID),
2555 int32(uniID),
2556 flowID, flowsToKVStore); err != nil {
2557 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2558 }
2559 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002560}
2561
salmansiddiqui7ac62132019-08-22 03:58:50 +00002562func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2563 if MeterID == 0 { // This should never happen
David K. Bainbridge794735f2020-02-11 21:01:37 -08002564 return "", NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002565 }
2566 if Dir == tp_pb.Direction_UPSTREAM {
2567 return "upstream", nil
2568 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2569 return "downstream", nil
2570 }
2571 return "", nil
2572}
2573
npujarec5762e2020-01-01 14:08:48 +05302574func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002575 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2576 TpID uint32, uni string) {
2577 var gemPort uint32
2578 intfID := args[IntfID]
2579 onuID := args[OnuID]
2580 uniID := args[UniID]
2581 portNo := args[PortNo]
2582 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002583 if ipProto, ok := classifierInfo[IPProto]; ok {
2584 if ipProto.(uint32) == IPProtoDhcp {
2585 log.Info("Adding DHCP flow")
2586 if pcp, ok := classifierInfo[VlanPcp]; ok {
2587 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2588 tp_pb.Direction_UPSTREAM,
2589 pcp.(uint32))
2590 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302591 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002592 } else {
2593 //Adding DHCP upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302594 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002595 }
2596
2597 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002598 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2599 if pcp, ok := classifierInfo[VlanPcp]; ok {
2600 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2601 tp_pb.Direction_UPSTREAM,
2602 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302603 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002604 } else {
2605 //Adding IGMP upstream flow to all gem ports
npujarec5762e2020-01-01 14:08:48 +05302606 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002607 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002608 } else {
2609 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2610 return
2611 }
2612 } else if ethType, ok := classifierInfo[EthType]; ok {
2613 if ethType.(uint32) == EapEthType {
2614 log.Info("Adding EAPOL flow")
2615 var vlanID uint32
2616 if val, ok := classifierInfo[VlanVid]; ok {
2617 vlanID = (val.(uint32)) & VlanvIDMask
2618 } else {
2619 vlanID = DefaultMgmtVlan
2620 }
2621 if pcp, ok := classifierInfo[VlanPcp]; ok {
2622 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2623 tp_pb.Direction_UPSTREAM,
2624 pcp.(uint32))
2625
npujarec5762e2020-01-01 14:08:48 +05302626 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, flow, allocID, gemPort, vlanID, classifierInfo, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002627 } else {
npujarec5762e2020-01-01 14:08:48 +05302628 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002629 }
2630 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002631 } else if _, ok := actionInfo[PushVlan]; ok {
2632 log.Info("Adding upstream data rule")
2633 if pcp, ok := classifierInfo[VlanPcp]; ok {
2634 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2635 tp_pb.Direction_UPSTREAM,
2636 pcp.(uint32))
2637 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302638 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002639 } else {
2640 //Adding HSIA upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302641 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002642 }
2643 } else if _, ok := actionInfo[PopVlan]; ok {
2644 log.Info("Adding Downstream data rule")
2645 if pcp, ok := classifierInfo[VlanPcp]; ok {
2646 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002647 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002648 pcp.(uint32))
2649 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302650 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002651 } else {
2652 //Adding HSIA downstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302653 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002654 }
2655 } else {
2656 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2657 return
2658 }
2659 // Send Techprofile download event to child device in go routine as it takes time
2660 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2661}
2662
Gamze Abakafee36392019-10-03 11:17:24 +00002663func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2664 flowIDList := f.flowsUsedByGemPort[gemPK]
2665 if len(flowIDList) > 1 {
2666 return true
2667 }
2668 return false
2669}
2670
npujarec5762e2020-01-01 14:08:48 +05302671func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2672 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002673 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2674 for _, currentGemPort := range currentGemPorts {
2675 for _, tpGemPort := range tpGemPorts {
2676 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2677 return true, currentGemPort
2678 }
2679 }
2680 }
Girish Gowdra54934262019-11-13 14:19:55 +05302681 if tpInst.InstanceCtrl.Onu == "single-instance" {
2682 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302683 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2684 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302685
2686 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2687 // still be used on other uni ports.
2688 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2689 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302690 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302691 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302692 for i := 0; i < len(tpInstances); i++ {
2693 tpI := tpInstances[i]
2694 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302695 for _, tpGemPort := range tpGemPorts {
2696 if tpGemPort.GemportID != gemPortID {
2697 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2698 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302699 }
2700 }
2701 }
2702 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302703 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002704 return false, 0
2705}
2706
salmansiddiqui7ac62132019-08-22 03:58:50 +00002707func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002708 for _, field := range flows.GetOfbFields(flow) {
2709 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002710 classifierInfo[EthType] = field.GetEthType()
2711 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002712 } else if field.Type == flows.ETH_DST {
2713 classifierInfo[EthDst] = field.GetEthDst()
2714 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002715 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002716 classifierInfo[IPProto] = field.GetIpProto()
2717 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002718 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002719 classifierInfo[InPort] = field.GetPort()
2720 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002721 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302722 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002723 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002724 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002725 classifierInfo[VlanPcp] = field.GetVlanPcp()
2726 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002727 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002728 classifierInfo[UDPDst] = field.GetUdpDst()
2729 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002730 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002731 classifierInfo[UDPSrc] = field.GetUdpSrc()
2732 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002733 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002734 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2735 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002736 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002737 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2738 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002739 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002740 classifierInfo[Metadata] = field.GetTableMetadata()
2741 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002742 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002743 classifierInfo[TunnelID] = field.GetTunnelId()
2744 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2745 } else {
2746 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2747 return
2748 }
2749 }
2750}
2751
2752func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002753 for _, action := range flows.GetActions(flow) {
2754 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002755 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002756 actionInfo[Output] = out.GetPort()
2757 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002758 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002759 return NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002760 }
Scott Baker355d1742019-10-24 10:57:52 -07002761 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002762 actionInfo[PopVlan] = true
2763 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002764 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002765 if out := action.GetPush(); out != nil {
2766 if tpid := out.GetEthertype(); tpid != 0x8100 {
2767 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2768 } else {
2769 actionInfo[PushVlan] = true
2770 actionInfo[TPID] = tpid
2771 log.Debugw("action-type-push-vlan",
2772 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2773 }
2774 }
Scott Baker355d1742019-10-24 10:57:52 -07002775 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002776 if out := action.GetSetField(); out != nil {
2777 if field := out.GetField(); field != nil {
2778 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002779 return NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002780 }
2781 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002782 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002783 }
2784 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002785 } else if action.Type == flows.GROUP {
2786 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002787 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002788 return NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002789 }
2790 }
2791 return nil
2792}
2793
Esin Karamanccb714b2019-11-29 15:02:06 +00002794func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2795 if ofbField := field.GetOfbField(); ofbField != nil {
2796 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2797 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2798 actionInfo[VlanVid] = vlan & 0xfff
2799 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2800 } else {
2801 log.Error("No Invalid vlan id in set vlan-vid action")
2802 }
2803 } else {
2804 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2805 }
2806 }
2807}
2808
2809func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2810 if action.GetGroup() == nil {
2811 log.Warn("No group entry found in the group action")
2812 } else {
2813 actionInfo[GroupID] = action.GetGroup().GroupId
2814 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2815 }
2816}
2817
salmansiddiqui7ac62132019-08-22 03:58:50 +00002818func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002819 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002820 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2821 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2822 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002823 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002824 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002825 log.Debugw("upstream pon-to-controller-flow,inport-in-tunnelid", log.Fields{"newInPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002826 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002827 return NewErrNotFound("child-in-port", log.Fields{
2828 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2829 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002830 }
2831 }
2832 } else {
2833 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2834 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002835 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002836 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002837 actionInfo[Output] = uniPort
2838 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[Output].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002839 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002840 return NewErrNotFound("out-port", log.Fields{
2841 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2842 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002843 }
2844 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2845 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002846 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002847 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002848 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2849 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002850 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002851 return NewErrNotFound("nni-port", log.Fields{
2852 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2853 "in-port": classifierInfo[InPort].(uint32),
2854 "out-port": actionInfo[Output].(uint32),
2855 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002856 }
2857 }
2858 }
2859 return nil
2860}
Gamze Abakafee36392019-10-03 11:17:24 +00002861
Chaitrashree G S90a17952019-11-14 21:51:21 -05002862func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002863 /* Metadata 8 bytes:
2864 Most Significant 2 Bytes = Inner VLAN
2865 Next 2 Bytes = Tech Profile ID(TPID)
2866 Least Significant 4 Bytes = Port ID
2867 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2868 subscriber related flows.
2869 */
2870 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2871 if metadata == 0 {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002872 return 0, NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002873 }
2874 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002875 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002876}
2877
2878func appendUnique(slice []uint32, item uint32) []uint32 {
2879 for _, sliceElement := range slice {
2880 if sliceElement == item {
2881 return slice
2882 }
2883 }
2884 return append(slice, item)
2885}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302886
2887// getNniIntfID gets nni intf id from the flow classifier/action
2888func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2889
2890 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2891 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002892 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2893 if err != nil {
2894 log.Debugw("invalid-action-port-number",
2895 log.Fields{
2896 "port-number": action[Output].(uint32),
2897 "error": err})
2898 return uint32(0), err
2899 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302900 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2901 return intfID, nil
2902 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002903 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2904 if err != nil {
2905 log.Debugw("invalid-classifier-port-number",
2906 log.Fields{
2907 "port-number": action[Output].(uint32),
2908 "error": err})
2909 return uint32(0), err
2910 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302911 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2912 return intfID, nil
2913 }
2914 return uint32(0), nil
2915}
2916
2917// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302918func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302919 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2920
2921 f.lockCache.Lock()
2922 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002923 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302924 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002925 if lookupGemPort == gemPort {
2926 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2927 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2928 return
2929 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302930 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002931 f.packetInGemPort[pktInkey] = gemPort
2932
npujarec5762e2020-01-01 14:08:48 +05302933 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002934 log.Debugw("pktin key not found in local cache or value is different. updating cache and kv store", log.Fields{"pktinkey": pktInkey, "gem": gemPort})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302935 return
2936}
2937
2938// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302939func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302940
2941 f.lockCache.Lock()
2942 defer f.lockCache.Unlock()
2943 onugem := f.onuGemInfo[intfID]
2944 for idx, onu := range onugem {
2945 if onu.OnuID == onuID {
2946 for _, uni := range onu.UniPorts {
2947 if uni == portNum {
2948 log.Debugw("uni already in cache, no need to update cache and kv store",
2949 log.Fields{"uni": portNum})
2950 return
2951 }
2952 }
2953 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2954 f.onuGemInfo[intfID] = onugem
2955 }
2956 }
npujarec5762e2020-01-01 14:08:48 +05302957 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302958}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302959
npujarec5762e2020-01-01 14:08:48 +05302960func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2961 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302962 if err != nil {
2963 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2964 return
2965 }
2966 for gem, FlowIDs := range flowIDsList {
2967 gemPK := gemPortKey{intf, uint32(gem)}
2968 f.flowsUsedByGemPort[gemPK] = FlowIDs
2969 }
2970 return
2971}
Esin Karamanccb714b2019-11-29 15:02:06 +00002972
2973//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2974//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302975func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2976 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002977 if err != nil {
2978 log.Error("Failed to get pon interface to multicast queue map")
2979 return
2980 }
2981 for intf, queueInfo := range storedMulticastQueueMap {
2982 q := queueInfoBrief{
2983 gemPortID: queueInfo[0],
2984 servicePriority: queueInfo[1],
2985 }
2986 f.interfaceToMcastQueueMap[intf] = &q
2987 }
2988}
2989
2990//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
2991//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
2992//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05302993func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
2994 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00002995 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002996 return nil, false, NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002997 }
2998 if exists {
2999 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3000 }
3001 return nil, exists, nil
3002}
3003
3004func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3005 groupDesc := ofp.OfpGroupDesc{
3006 Type: ofp.OfpGroupType_OFPGT_ALL,
3007 GroupId: groupID,
3008 }
3009 groupEntry := ofp.OfpGroupEntry{
3010 Desc: &groupDesc,
3011 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003012 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003013 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003014 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003015 bucket := ofp.OfpBucket{
3016 Actions: acts,
3017 }
3018 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003019 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003020 return &groupEntry
3021}