blob: 578861d0f1c7f46f594b4bb85fb394e445fdc553 [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)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002232 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2233 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302234 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2235 return
2236 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002237 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2238}
2239
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302240//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302241func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302242 f.lockCache.Lock()
2243 defer f.lockCache.Unlock()
2244 onugem := f.onuGemInfo[intfID]
2245 // update the gem to the local cache as well as to kv strore
2246 for idx, onu := range onugem {
2247 if onu.OnuID == onuID {
2248 // check if gem already exists , else update the cache and kvstore
2249 for _, gem := range onu.GemPorts {
2250 if gem == gemPort {
2251 log.Debugw("Gem already in cache, no need to update cache and kv store",
2252 log.Fields{"gem": gemPort})
2253 return
2254 }
2255 }
2256 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2257 f.onuGemInfo[intfID] = onugem
2258 }
2259 }
npujarec5762e2020-01-01 14:08:48 +05302260 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302261 if err != nil {
2262 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002263 return
2264 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002265}
2266
2267// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002268
2269//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2270func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302271
2272 f.lockCache.Lock()
2273 defer f.lockCache.Unlock()
2274
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002275 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 +05302276 // get onuid from the onugem info cache
2277 onugem := f.onuGemInfo[intfID]
2278 for _, onu := range onugem {
2279 for _, gem := range onu.GemPorts {
2280 if gem == gemPortID {
2281 return onu.OnuID, nil
2282 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002283 }
2284 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002285 return uint32(0), NewErrNotFound("onu-id", log.Fields{
2286 "serial-number": serialNumber,
2287 "interface-id": intfID,
2288 "gem-port-id": gemPortID},
2289 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002290}
2291
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002292//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302293func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002294 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002295 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002296 var err error
2297
2298 if packetIn.IntfType == "pon" {
2299 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002300 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002301 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2302 return logicalPortNum, err
2303 }
2304 if packetIn.PortNo != 0 {
2305 logicalPortNum = packetIn.PortNo
2306 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002307 uniID := uint32(0) // FIXME - multi-uni support
2308 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002309 }
2310 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302311 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002312 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002313 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002314 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002315 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2316 "logicalPortNum": logicalPortNum,
2317 "IntfType": packetIn.IntfType,
2318 "packet": hex.EncodeToString(packetIn.Pkt),
2319 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002320 return logicalPortNum, nil
2321}
2322
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002323//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302324func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002325 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002326 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302327
2328 f.lockCache.Lock()
2329 defer f.lockCache.Unlock()
2330 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2331
2332 gemPortID, ok := f.packetInGemPort[pktInkey]
2333 if ok {
2334 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2335 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002336 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302337 //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 +05302338 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302339 if err == nil {
2340 if gemPortID != 0 {
2341 f.packetInGemPort[pktInkey] = gemPortID
2342 log.Debugw("Found gem port from kv store and updating cache with gemport",
2343 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2344 return gemPortID, nil
2345 }
2346 }
2347 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2348 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002349}
2350
npujarec5762e2020-01-01 14:08:48 +05302351func installFlowOnAllGemports(ctx context.Context,
2352 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002353 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002354 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302355 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302356 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
David K. Bainbridge794735f2020-02-11 21:01:37 -08002357 classifier map[string]interface{}, action map[string]interface{}) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002358 args map[string]uint32,
2359 classifier map[string]interface{}, action map[string]interface{},
2360 logicalFlow *ofp.OfpFlowStats,
2361 gemPorts []uint32,
2362 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002363 vlanID ...uint32) {
2364 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
2365 for _, gemPortID := range gemPorts {
Manikkaraj kb1d51442019-07-23 10:41:02 -04002366 if FlowType == HsiaFlow || FlowType == DhcpFlow {
npujarec5762e2020-01-01 14:08:48 +05302367 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002368 } else if FlowType == EapolFlow {
npujarec5762e2020-01-01 14:08:48 +05302369 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 -04002370 } else {
2371 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2372 return
2373 }
2374 }
2375}
2376
David K. Bainbridge794735f2020-02-11 21:01:37 -08002377func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002378 log.Debug("Adding trap-dhcp-of-nni-flow")
2379 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002380 classifier[PacketTagType] = DoubleTag
2381 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002382 /* We manage flowId resource pool on per PON port basis.
2383 Since this situation is tricky, as a hack, we pass the NNI port
2384 index (network_intf_id) as PON port Index for the flowId resource
2385 pool. Also, there is no ONU Id available for trapping DHCP packets
2386 on NNI port, use onu_id as -1 (invalid)
2387 ****************** CAVEAT *******************
2388 This logic works if the NNI Port Id falls within the same valid
2389 range of PON Port Ids. If this doesn't work for some OLT Vendor
2390 we need to have a re-look at this.
2391 *********************************************
2392 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002393 onuID := -1
2394 uniID := -1
2395 gemPortID := -1
2396 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002397 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302398 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002399 return NewErrNotFound("nni-intreface-id", log.Fields{
2400 "classifier": classifier,
2401 "action": action},
2402 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302403 }
2404
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002405 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302406 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002407 log.Debug("Flow-exists-not-re-adding")
2408 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002409 }
npujarec5762e2020-01-01 14:08:48 +05302410 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002411 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002412 return NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
2413 "interface-id": networkInterfaceID,
2414 "onu-id": onuID,
2415 "uni-id": uniID,
2416 "gem-port-id": gemPortID,
2417 "cookie": flowStoreCookie},
2418 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002419 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002420 classifierProto, err := makeOpenOltClassifierField(classifier)
2421 if err != nil {
2422 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002423 }
2424 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002425 actionProto, err := makeOpenOltActionField(action)
2426 if err != nil {
2427 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002428 }
2429 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002430 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2431 OnuId: int32(onuID), // OnuId not required
2432 UniId: int32(uniID), // UniId not used
2433 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002434 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002435 AllocId: int32(allocID), // AllocId not used
2436 NetworkIntfId: int32(networkInterfaceID),
2437 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002438 Classifier: classifierProto,
2439 Action: actionProto,
2440 Priority: int32(logicalFlow.Priority),
2441 Cookie: logicalFlow.Cookie,
2442 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002443 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2444 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002445 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002446 log.Debug("DHCP trap on NNI flow added to device successfully")
2447 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2448 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2449 int32(onuID),
2450 int32(uniID),
2451 flowID, flowsToKVStore); err != nil {
2452 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2453 }
2454 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002455}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002456
Esin Karamanae41e2b2019-12-17 18:13:13 +00002457//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2458func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2459 var packetType string
2460 ovid, ivid := false, false
2461 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2462 vid := vlanID & VlanvIDMask
2463 if vid != ReservedVlan {
2464 ovid = true
2465 }
2466 }
2467 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2468 vid := uint32(metadata)
2469 if vid != ReservedVlan {
2470 ivid = true
2471 }
2472 }
2473 if ovid && ivid {
2474 packetType = DoubleTag
2475 } else if !ovid && !ivid {
2476 packetType = Untagged
2477 } else {
2478 packetType = SingleTag
2479 }
2480 return packetType
2481}
2482
2483//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002484func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002485 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2486 action := make(map[string]interface{})
2487 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2488 action[TrapToHost] = true
2489 /* We manage flowId resource pool on per PON port basis.
2490 Since this situation is tricky, as a hack, we pass the NNI port
2491 index (network_intf_id) as PON port Index for the flowId resource
2492 pool. Also, there is no ONU Id available for trapping packets
2493 on NNI port, use onu_id as -1 (invalid)
2494 ****************** CAVEAT *******************
2495 This logic works if the NNI Port Id falls within the same valid
2496 range of PON Port Ids. If this doesn't work for some OLT Vendor
2497 we need to have a re-look at this.
2498 *********************************************
2499 */
2500 onuID := -1
2501 uniID := -1
2502 gemPortID := -1
2503 allocID := -1
2504 networkInterfaceID, err := getNniIntfID(classifier, action)
2505 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002506 return NewErrNotFound("nni-interface-id", log.Fields{
2507 "classifier": classifier,
2508 "action": action},
2509 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002510 }
2511 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302512 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002513 log.Debug("igmp-flow-exists-not-re-adding")
2514 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002515 }
npujarec5762e2020-01-01 14:08:48 +05302516 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002517 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002518 return NewErrNotFound("igmp-flow-id", log.Fields{
2519 "interface-id": networkInterfaceID,
2520 "onu-id": onuID,
2521 "uni-id": uniID,
2522 "gem-port-id": gemPortID,
2523 "cookie": flowStoreCookie},
2524 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002525 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002526 classifierProto, err := makeOpenOltClassifierField(classifier)
2527 if err != nil {
2528 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002529 }
2530 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002531 actionProto, err := makeOpenOltActionField(action)
2532 if err != nil {
2533 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002534 }
2535 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2536 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2537 OnuId: int32(onuID), // OnuId not required
2538 UniId: int32(uniID), // UniId not used
2539 FlowId: flowID,
2540 FlowType: Downstream,
2541 AllocId: int32(allocID), // AllocId not used
2542 NetworkIntfId: int32(networkInterfaceID),
2543 GemportId: int32(gemPortID), // GemportId not used
2544 Classifier: classifierProto,
2545 Action: actionProto,
2546 Priority: int32(logicalFlow.Priority),
2547 Cookie: logicalFlow.Cookie,
2548 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002549 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2550 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002551 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002552 log.Debug("IGMP Trap on NNI flow added to device successfully")
2553 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2554 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2555 int32(onuID),
2556 int32(uniID),
2557 flowID, flowsToKVStore); err != nil {
2558 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2559 }
2560 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002561}
2562
salmansiddiqui7ac62132019-08-22 03:58:50 +00002563func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2564 if MeterID == 0 { // This should never happen
David K. Bainbridge794735f2020-02-11 21:01:37 -08002565 return "", NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002566 }
2567 if Dir == tp_pb.Direction_UPSTREAM {
2568 return "upstream", nil
2569 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2570 return "downstream", nil
2571 }
2572 return "", nil
2573}
2574
npujarec5762e2020-01-01 14:08:48 +05302575func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002576 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2577 TpID uint32, uni string) {
2578 var gemPort uint32
2579 intfID := args[IntfID]
2580 onuID := args[OnuID]
2581 uniID := args[UniID]
2582 portNo := args[PortNo]
2583 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002584 if ipProto, ok := classifierInfo[IPProto]; ok {
2585 if ipProto.(uint32) == IPProtoDhcp {
2586 log.Info("Adding DHCP flow")
2587 if pcp, ok := classifierInfo[VlanPcp]; ok {
2588 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2589 tp_pb.Direction_UPSTREAM,
2590 pcp.(uint32))
2591 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302592 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002593 } else {
2594 //Adding DHCP upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302595 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002596 }
2597
2598 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002599 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2600 if pcp, ok := classifierInfo[VlanPcp]; ok {
2601 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2602 tp_pb.Direction_UPSTREAM,
2603 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302604 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002605 } else {
2606 //Adding IGMP upstream flow to all gem ports
npujarec5762e2020-01-01 14:08:48 +05302607 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002608 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002609 } else {
2610 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2611 return
2612 }
2613 } else if ethType, ok := classifierInfo[EthType]; ok {
2614 if ethType.(uint32) == EapEthType {
2615 log.Info("Adding EAPOL flow")
2616 var vlanID uint32
2617 if val, ok := classifierInfo[VlanVid]; ok {
2618 vlanID = (val.(uint32)) & VlanvIDMask
2619 } else {
2620 vlanID = DefaultMgmtVlan
2621 }
2622 if pcp, ok := classifierInfo[VlanPcp]; ok {
2623 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2624 tp_pb.Direction_UPSTREAM,
2625 pcp.(uint32))
2626
npujarec5762e2020-01-01 14:08:48 +05302627 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, flow, allocID, gemPort, vlanID, classifierInfo, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002628 } else {
npujarec5762e2020-01-01 14:08:48 +05302629 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002630 }
2631 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002632 } else if _, ok := actionInfo[PushVlan]; ok {
2633 log.Info("Adding upstream data rule")
2634 if pcp, ok := classifierInfo[VlanPcp]; ok {
2635 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2636 tp_pb.Direction_UPSTREAM,
2637 pcp.(uint32))
2638 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302639 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002640 } else {
2641 //Adding HSIA upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302642 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002643 }
2644 } else if _, ok := actionInfo[PopVlan]; ok {
2645 log.Info("Adding Downstream data rule")
2646 if pcp, ok := classifierInfo[VlanPcp]; ok {
2647 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002648 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002649 pcp.(uint32))
2650 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302651 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002652 } else {
2653 //Adding HSIA downstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302654 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002655 }
2656 } else {
2657 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2658 return
2659 }
2660 // Send Techprofile download event to child device in go routine as it takes time
2661 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2662}
2663
Gamze Abakafee36392019-10-03 11:17:24 +00002664func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2665 flowIDList := f.flowsUsedByGemPort[gemPK]
2666 if len(flowIDList) > 1 {
2667 return true
2668 }
2669 return false
2670}
2671
npujarec5762e2020-01-01 14:08:48 +05302672func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2673 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002674 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2675 for _, currentGemPort := range currentGemPorts {
2676 for _, tpGemPort := range tpGemPorts {
2677 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2678 return true, currentGemPort
2679 }
2680 }
2681 }
Girish Gowdra54934262019-11-13 14:19:55 +05302682 if tpInst.InstanceCtrl.Onu == "single-instance" {
2683 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302684 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2685 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302686
2687 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2688 // still be used on other uni ports.
2689 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2690 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302691 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302692 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302693 for i := 0; i < len(tpInstances); i++ {
2694 tpI := tpInstances[i]
2695 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302696 for _, tpGemPort := range tpGemPorts {
2697 if tpGemPort.GemportID != gemPortID {
2698 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2699 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302700 }
2701 }
2702 }
2703 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302704 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002705 return false, 0
2706}
2707
salmansiddiqui7ac62132019-08-22 03:58:50 +00002708func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002709 for _, field := range flows.GetOfbFields(flow) {
2710 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002711 classifierInfo[EthType] = field.GetEthType()
2712 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002713 } else if field.Type == flows.ETH_DST {
2714 classifierInfo[EthDst] = field.GetEthDst()
2715 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002716 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002717 classifierInfo[IPProto] = field.GetIpProto()
2718 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002719 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002720 classifierInfo[InPort] = field.GetPort()
2721 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002722 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302723 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002724 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002725 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002726 classifierInfo[VlanPcp] = field.GetVlanPcp()
2727 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002728 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002729 classifierInfo[UDPDst] = field.GetUdpDst()
2730 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002731 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002732 classifierInfo[UDPSrc] = field.GetUdpSrc()
2733 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002734 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002735 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2736 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002737 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002738 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2739 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002740 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002741 classifierInfo[Metadata] = field.GetTableMetadata()
2742 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002743 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002744 classifierInfo[TunnelID] = field.GetTunnelId()
2745 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2746 } else {
2747 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2748 return
2749 }
2750 }
2751}
2752
2753func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002754 for _, action := range flows.GetActions(flow) {
2755 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002756 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002757 actionInfo[Output] = out.GetPort()
2758 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002759 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002760 return NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002761 }
Scott Baker355d1742019-10-24 10:57:52 -07002762 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002763 actionInfo[PopVlan] = true
2764 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002765 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002766 if out := action.GetPush(); out != nil {
2767 if tpid := out.GetEthertype(); tpid != 0x8100 {
2768 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2769 } else {
2770 actionInfo[PushVlan] = true
2771 actionInfo[TPID] = tpid
2772 log.Debugw("action-type-push-vlan",
2773 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2774 }
2775 }
Scott Baker355d1742019-10-24 10:57:52 -07002776 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002777 if out := action.GetSetField(); out != nil {
2778 if field := out.GetField(); field != nil {
2779 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002780 return NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002781 }
2782 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002783 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002784 }
2785 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002786 } else if action.Type == flows.GROUP {
2787 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002788 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002789 return NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002790 }
2791 }
2792 return nil
2793}
2794
Esin Karamanccb714b2019-11-29 15:02:06 +00002795func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2796 if ofbField := field.GetOfbField(); ofbField != nil {
2797 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2798 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2799 actionInfo[VlanVid] = vlan & 0xfff
2800 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2801 } else {
2802 log.Error("No Invalid vlan id in set vlan-vid action")
2803 }
2804 } else {
2805 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2806 }
2807 }
2808}
2809
2810func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2811 if action.GetGroup() == nil {
2812 log.Warn("No group entry found in the group action")
2813 } else {
2814 actionInfo[GroupID] = action.GetGroup().GroupId
2815 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2816 }
2817}
2818
salmansiddiqui7ac62132019-08-22 03:58:50 +00002819func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002820 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002821 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2822 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2823 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002824 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002825 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002826 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 +00002827 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002828 return NewErrNotFound("child-in-port", log.Fields{
2829 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2830 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002831 }
2832 }
2833 } else {
2834 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2835 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002836 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002837 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002838 actionInfo[Output] = uniPort
2839 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 +00002840 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002841 return NewErrNotFound("out-port", log.Fields{
2842 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2843 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002844 }
2845 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2846 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002847 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002848 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002849 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2850 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002851 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002852 return NewErrNotFound("nni-port", log.Fields{
2853 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2854 "in-port": classifierInfo[InPort].(uint32),
2855 "out-port": actionInfo[Output].(uint32),
2856 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002857 }
2858 }
2859 }
2860 return nil
2861}
Gamze Abakafee36392019-10-03 11:17:24 +00002862
Chaitrashree G S90a17952019-11-14 21:51:21 -05002863func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002864 /* Metadata 8 bytes:
2865 Most Significant 2 Bytes = Inner VLAN
2866 Next 2 Bytes = Tech Profile ID(TPID)
2867 Least Significant 4 Bytes = Port ID
2868 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2869 subscriber related flows.
2870 */
2871 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2872 if metadata == 0 {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002873 return 0, NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002874 }
2875 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002876 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002877}
2878
2879func appendUnique(slice []uint32, item uint32) []uint32 {
2880 for _, sliceElement := range slice {
2881 if sliceElement == item {
2882 return slice
2883 }
2884 }
2885 return append(slice, item)
2886}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302887
2888// getNniIntfID gets nni intf id from the flow classifier/action
2889func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2890
2891 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2892 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002893 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2894 if err != nil {
2895 log.Debugw("invalid-action-port-number",
2896 log.Fields{
2897 "port-number": action[Output].(uint32),
2898 "error": err})
2899 return uint32(0), err
2900 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302901 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2902 return intfID, nil
2903 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002904 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2905 if err != nil {
2906 log.Debugw("invalid-classifier-port-number",
2907 log.Fields{
2908 "port-number": action[Output].(uint32),
2909 "error": err})
2910 return uint32(0), err
2911 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302912 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2913 return intfID, nil
2914 }
2915 return uint32(0), nil
2916}
2917
2918// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302919func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302920 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2921
2922 f.lockCache.Lock()
2923 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002924 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302925 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002926 if lookupGemPort == gemPort {
2927 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2928 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2929 return
2930 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302931 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002932 f.packetInGemPort[pktInkey] = gemPort
2933
npujarec5762e2020-01-01 14:08:48 +05302934 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002935 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 +05302936 return
2937}
2938
2939// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302940func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302941
2942 f.lockCache.Lock()
2943 defer f.lockCache.Unlock()
2944 onugem := f.onuGemInfo[intfID]
2945 for idx, onu := range onugem {
2946 if onu.OnuID == onuID {
2947 for _, uni := range onu.UniPorts {
2948 if uni == portNum {
2949 log.Debugw("uni already in cache, no need to update cache and kv store",
2950 log.Fields{"uni": portNum})
2951 return
2952 }
2953 }
2954 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2955 f.onuGemInfo[intfID] = onugem
2956 }
2957 }
npujarec5762e2020-01-01 14:08:48 +05302958 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302959}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302960
npujarec5762e2020-01-01 14:08:48 +05302961func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2962 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302963 if err != nil {
2964 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2965 return
2966 }
2967 for gem, FlowIDs := range flowIDsList {
2968 gemPK := gemPortKey{intf, uint32(gem)}
2969 f.flowsUsedByGemPort[gemPK] = FlowIDs
2970 }
2971 return
2972}
Esin Karamanccb714b2019-11-29 15:02:06 +00002973
2974//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2975//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302976func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2977 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002978 if err != nil {
2979 log.Error("Failed to get pon interface to multicast queue map")
2980 return
2981 }
2982 for intf, queueInfo := range storedMulticastQueueMap {
2983 q := queueInfoBrief{
2984 gemPortID: queueInfo[0],
2985 servicePriority: queueInfo[1],
2986 }
2987 f.interfaceToMcastQueueMap[intf] = &q
2988 }
2989}
2990
2991//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
2992//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
2993//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05302994func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
2995 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00002996 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002997 return nil, false, NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002998 }
2999 if exists {
3000 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3001 }
3002 return nil, exists, nil
3003}
3004
3005func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3006 groupDesc := ofp.OfpGroupDesc{
3007 Type: ofp.OfpGroupType_OFPGT_ALL,
3008 GroupId: groupID,
3009 }
3010 groupEntry := ofp.OfpGroupEntry{
3011 Desc: &groupDesc,
3012 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003013 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003014 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003015 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003016 bucket := ofp.OfpBucket{
3017 Actions: acts,
3018 }
3019 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003020 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003021 return &groupEntry
3022}