blob: 5a4225ae200333af12faf88b25e8a6d442576fcb [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]
1478 for _, onu := range onugem {
1479 if onu.OnuID == onuID {
1480 for i, gem := range onu.GemPorts {
1481 // If the gemport is found, delete it from local cache.
1482 if gem == gemPortID {
1483 onu.GemPorts = append(onu.GemPorts[:i], onu.GemPorts[i+1:]...)
1484 log.Debugw("removed gemport from local cache",
1485 log.Fields{"intfID": intfID, "onuID": onuID, "gemPortID": gemPortID})
1486 break
1487 }
1488 }
1489 break
1490 }
1491 }
1492}
1493
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301494//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301495func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301496 gemPortID int32, flowID uint32, flowDirection string,
1497 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001498
Chaitrashree G S90a17952019-11-14 21:51:21 -05001499 tpID, err := getTpIDFromFlow(flow)
1500 if err != nil {
1501 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1502 return err
1503 }
Gamze Abakafee36392019-10-03 11:17:24 +00001504
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001505 if len(updatedFlows) >= 0 {
1506 // There are still flows referencing the same flow_id.
1507 // So the flow should not be freed yet.
1508 // For ex: Case of HSIA where same flow is shared
1509 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301510 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001511 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301512 // Do this for subscriber flows only (not trap from NNI flows)
1513 if onuID != -1 && uniID != -1 {
1514 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1515 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1516 log.Debugw("creating entry for pending flow delete",
1517 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1518 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1519 } else {
1520 pnFlDels := val.(int) + 1
1521 log.Debugw("updating flow delete entry",
1522 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1523 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1524 }
1525
1526 defer f.deletePendingFlows(Intf, onuID, uniID)
1527 }
1528
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301529 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301530 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001531
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301532 uni := getUniPortPath(Intf, onuID, uniID)
1533 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001534 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301535 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001536 if err != nil { // This should not happen, something wrong in KV backend transaction
1537 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301538 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001539 }
1540 if techprofileInst == nil {
1541 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301542 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001543 }
1544
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301545 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001546 if f.isGemPortUsedByAnotherFlow(gemPK) {
1547 flowIDs := f.flowsUsedByGemPort[gemPK]
1548 for i, flowIDinMap := range flowIDs {
1549 if flowIDinMap == flowID {
1550 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301551 // everytime flowsUsedByGemPort cache is updated the same should be updated
1552 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001553 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301554 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001555 break
1556 }
1557 }
1558 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301559 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001560 }
Gamze Abakafee36392019-10-03 11:17:24 +00001561 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301562 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001563 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1564 // 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 +05301565 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301566 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001567 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301568 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1569 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001570 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301571 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1572 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001573 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301574 // Delete the gem port on the ONU.
1575 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1576 log.Errorw("error processing delete gem-port towards onu",
1577 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1578 }
Gamze Abakafee36392019-10-03 11:17:24 +00001579
npujarec5762e2020-01-01 14:08:48 +05301580 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001581 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301582 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1583 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1584 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1585 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1586 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301587 // Delete the TCONT on the ONU.
1588 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1589 log.Errorw("error processing delete tcont towards onu",
1590 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1591 }
Gamze Abakafee36392019-10-03 11:17:24 +00001592 }
1593 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001594 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301595 return nil
1596}
1597
David K. Bainbridge794735f2020-02-11 21:01:37 -08001598// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301599func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301600
1601 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001602
1603 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301604 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001605 return
1606 }
1607
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301608 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301609 classifierInfo := make(map[string]interface{})
1610
1611 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1612 if err != nil {
1613 log.Error(err)
1614 return
1615 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301616
David K. Bainbridge794735f2020-02-11 21:01:37 -08001617 onuID := int32(onu)
1618 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301619
1620 for _, field := range flows.GetOfbFields(flow) {
1621 if field.Type == flows.IP_PROTO {
1622 classifierInfo[IPProto] = field.GetIpProto()
1623 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1624 }
1625 }
1626 log.Debugw("Extracted access info from flow to be deleted",
1627 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1628
1629 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1630 onuID = -1
1631 uniID = -1
1632 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001633 Intf, err = IntfIDFromNniPortNum(inPort)
1634 if err != nil {
1635 log.Errorw("invalid-in-port-number",
1636 log.Fields{
1637 "port-number": inPort,
1638 "error": err})
1639 return
1640 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301641 }
npujarec5762e2020-01-01 14:08:48 +05301642 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001643 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301644 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301645 if flowInfo == nil {
1646 log.Debugw("No FlowInfo found found in KV store",
1647 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1648 return
1649 }
1650 updatedFlows = nil
1651 for _, flow := range *flowInfo {
1652 updatedFlows = append(updatedFlows, flow)
1653 }
1654
1655 for i, storedFlow := range updatedFlows {
1656 if flow.Id == storedFlow.LogicalFlowID {
1657 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1658 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001659 // DKB
1660 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1661 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1662 return
1663 }
1664 log.Debug("Flow removed from device successfully")
1665 //Remove the Flow from FlowInfo
1666 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1667 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1668 flowID, flowDirection, portNum, updatedFlows); err != nil {
1669 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301670 return
1671 }
1672 }
1673 }
1674 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001675}
1676
Esin Karamanccb714b2019-11-29 15:02:06 +00001677//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1678// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301679func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001680 classifierInfo := make(map[string]interface{})
1681 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301682 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001683
1684 if err != nil {
1685 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1686 return
1687 }
1688
David K. Bainbridge794735f2020-02-11 21:01:37 -08001689 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1690 if err != nil {
1691 // DKB
1692 log.Errorw("invalid-in-port-number",
1693 log.Fields{
1694 "port-number": inPort,
1695 "error": err})
1696 return
1697 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001698 var onuID = int32(NoneOnuID)
1699 var uniID = int32(NoneUniID)
1700 var flowID uint32
1701 var updatedFlows []rsrcMgr.FlowInfo
1702
npujarec5762e2020-01-01 14:08:48 +05301703 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001704
1705 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301706 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001707 if flowInfo == nil {
1708 log.Debugw("No multicast FlowInfo found in the KV store",
1709 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1710 continue
1711 }
1712 updatedFlows = nil
1713 for _, flow := range *flowInfo {
1714 updatedFlows = append(updatedFlows, flow)
1715 }
1716 for i, storedFlow := range updatedFlows {
1717 if flow.Id == storedFlow.LogicalFlowID {
1718 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1719 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1720 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001721 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1722 // DKB
1723 log.Errorw("failed-to-remove-multicast-flow",
1724 log.Fields{
1725 "flow-id": flow.Id,
1726 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001727 return
1728 }
1729 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1730 //Remove the Flow from FlowInfo
1731 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301732 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001733 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1734 return
1735 }
1736 //release flow id
1737 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301738 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001739 }
1740 }
1741 }
1742}
1743
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001744//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301745func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001746 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301747 var direction string
1748 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001749
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301750 for _, action := range flows.GetActions(flow) {
1751 if action.Type == flows.OUTPUT {
1752 if out := action.GetOutput(); out != nil {
1753 actionInfo[Output] = out.GetPort()
1754 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1755 } else {
1756 log.Error("Invalid output port in action")
1757 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001758 }
1759 }
1760 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001761
1762 if flows.HasGroup(flow) {
1763 direction = Multicast
1764 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301765 direction = Upstream
1766 } else {
1767 direction = Downstream
1768 }
npujarec5762e2020-01-01 14:08:48 +05301769 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301770
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001771 return
1772}
1773
Girish Gowdra3d633032019-12-10 16:37:05 +05301774func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1775 uniID uint32, ch chan bool) {
1776 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1777 for {
1778 select {
1779 case <-time.After(20 * time.Millisecond):
1780 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1781 log.Debug("pending flow deletes completed")
1782 ch <- true
1783 return
1784 }
1785 case <-ctx.Done():
1786 log.Error("flow delete wait handler routine canceled")
1787 return
1788 }
1789 }
1790}
1791
Esin Karamanae41e2b2019-12-17 18:13:13 +00001792//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1793func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1794 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1795 if ethType, ok := classifierInfo[EthType]; ok {
1796 if ethType.(uint32) == IPv4EthType {
1797 if ipProto, ok := classifierInfo[IPProto]; ok {
1798 if ipProto.(uint32) == IgmpProto {
1799 return true
1800 }
1801 }
1802 }
1803 }
1804 }
1805 return false
1806}
1807
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001808// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301809// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301810func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001811 classifierInfo := make(map[string]interface{})
1812 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001813 var UsMeterID uint32
1814 var DsMeterID uint32
1815
1816 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001817 formulateClassifierInfoFromFlow(classifierInfo, flow)
1818
1819 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1820 if err != nil {
1821 // Error logging is already done in the called function
1822 // So just return in case of error
1823 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301824 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001825
Esin Karamanccb714b2019-11-29 15:02:06 +00001826 if flows.HasGroup(flow) {
1827 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301828 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001829 return
1830 }
1831
manikkaraj k17652a72019-05-06 09:06:36 -04001832 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001833 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1834 if err != nil {
1835 // error if any, already logged in the called function
1836 return
manikkaraj k17652a72019-05-06 09:06:36 -04001837 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001838
David K. Bainbridge82efc492019-09-04 09:57:11 -07001839 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1840 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001841
Humera Kouser94d7a842019-08-25 19:04:32 -04001842 if ethType, ok := classifierInfo[EthType]; ok {
1843 if ethType.(uint32) == LldpEthType {
1844 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301845 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001846 return
1847 }
1848 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001849 if ipProto, ok := classifierInfo[IPProto]; ok {
1850 if ipProto.(uint32) == IPProtoDhcp {
1851 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301852 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001853 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301854 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001855 return
1856 }
1857 }
1858 }
1859 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001860 if isIgmpTrapDownstreamFlow(classifierInfo) {
1861 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301862 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001863 return
1864 }
A R Karthick1f85b802019-10-11 05:06:05 +00001865
1866 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301867 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001868
Chaitrashree G S90a17952019-11-14 21:51:21 -05001869 TpID, err := getTpIDFromFlow(flow)
1870 if err != nil {
1871 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1872 return
1873 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001874 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001875 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001876 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001877 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1878 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001879 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001880 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1881
1882 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301883
1884 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1885 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1886 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 +05301887 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301888 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301889 pendingFlowDelComplete := make(chan bool)
1890 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1891 select {
1892 case <-pendingFlowDelComplete:
1893 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301894 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301895
1896 case <-time.After(10 * time.Second):
1897 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1898 }
1899 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001900}
1901
Esin Karamanccb714b2019-11-29 15:02:06 +00001902// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001903func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001904 classifierInfo[PacketTagType] = DoubleTag
1905 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1906
npujarec5762e2020-01-01 14:08:48 +05301907 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001908 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001909 return NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001910 }
1911 //replace ipDst with ethDst
1912 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1913 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1914 // replace ipv4_dst classifier with eth_dst
1915 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1916 delete(classifierInfo, Ipv4Dst)
1917 delete(classifierInfo, EthType)
1918 classifierInfo[EthDst] = multicastMac
1919 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1920 }
1921
David K. Bainbridge794735f2020-02-11 21:01:37 -08001922 onuID := NoneOnuID
1923 uniID := NoneUniID
1924 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001925
David K. Bainbridge794735f2020-02-11 21:01:37 -08001926 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1927 if err != nil {
1928 return NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
1929 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001930
David K. Bainbridge794735f2020-02-11 21:01:37 -08001931 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301932 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001933 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1934 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001935 }
npujarec5762e2020-01-01 14:08:48 +05301936 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001937 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001938 return NewErrNotFound("multicast-flow-id", log.Fields{
1939 "interface-id": networkInterfaceID,
1940 "onu-id": onuID,
1941 "uni-id": uniID,
1942 "gem-port-id": gemPortID,
1943 "cookie": flowStoreCookie},
1944 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001945 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001946 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1947 if err != nil {
1948 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001949 }
1950 groupID := actionInfo[GroupID].(uint32)
1951 multicastFlow := openoltpb2.Flow{
1952 FlowId: flowID,
1953 FlowType: Multicast,
1954 NetworkIntfId: int32(networkInterfaceID),
1955 GroupId: groupID,
1956 Classifier: classifierProto,
1957 Priority: int32(flow.Priority),
1958 Cookie: flow.Cookie}
1959
David K. Bainbridge794735f2020-02-11 21:01:37 -08001960 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
1961 return NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1962 }
1963 log.Debug("multicast flow added to device successfully")
1964 //get cached group
1965 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1966 if err == nil {
1967 //calling groupAdd to set group members after multicast flow creation
1968 if f.ModifyGroup(ctx, group) {
1969 //cached group can be removed now
1970 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001971 }
1972 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001973
1974 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1975 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1976 int32(onuID),
1977 int32(uniID),
1978 flowID, flowsToKVStore); err != nil {
1979 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1980 }
1981 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001982}
1983
1984//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301985func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001986 if _, ok := classifierInfo[InPort]; ok {
1987 return classifierInfo[InPort].(uint32), nil
1988 }
1989 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301990 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001991 if e == nil && len(nniPorts) > 0 {
1992 return nniPorts[0], nil
1993 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001994 return 0, NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001995}
1996
1997// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05301998func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001999 log.Infow("add-group", log.Fields{"group": group})
2000 if group == nil {
2001 log.Warn("skipping nil group")
2002 return
2003 }
2004
2005 groupToOlt := openoltpb2.Group{
2006 GroupId: group.Desc.GroupId,
2007 Command: openoltpb2.Group_SET_MEMBERS,
2008 Action: f.buildGroupAction(),
2009 }
2010
2011 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302012 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002013 if err != nil {
2014 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
2015 return
2016 }
2017 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302018 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002019 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
2020 } else {
2021 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2022 }
2023}
2024
2025//buildGroupAction creates and returns a group action
2026func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2027 var actionCmd openoltpb2.ActionCmd
2028 var action openoltpb2.Action
2029 action.Cmd = &actionCmd
2030 //pop outer vlan
2031 action.Cmd.RemoveOuterTag = true
2032 return &action
2033}
2034
2035// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05302036func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00002037 log.Infow("modify-group", log.Fields{"group": group})
2038 if group == nil || group.Desc == nil {
2039 log.Warn("cannot modify group; group is nil")
2040 return false
2041 }
2042
2043 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2044 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302045 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002046
2047 if err != nil {
2048 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2049 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2050 return false
2051 }
2052
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002053 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002054 if groupExists {
2055 // group already exists
2056 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002057 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002058 } else {
2059 current = f.buildGroup(group.Desc.GroupId, nil)
2060 }
2061
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002062 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2063 // get members to be added
2064 membersToBeAdded := f.findDiff(current, new)
2065 // get members to be removed
2066 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002067
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002068 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2069 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002070
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002071 groupToOlt := openoltpb2.Group{
2072 GroupId: group.Desc.GroupId,
2073 }
2074 var added, removed = true, true
2075 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2076 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2077 groupToOlt.Members = membersToBeAdded
2078 //execute addMembers
2079 added = f.callGroupAddRemove(&groupToOlt)
2080 }
2081 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2082 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2083 groupToOlt.Members = membersToBeRemoved
2084 //execute removeMembers
2085 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002086 }
2087
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002088 //save the modified group
2089 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302090 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002091 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2092 }
2093 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002094 } else {
2095 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2096 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002097 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002098 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002099}
2100
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002101//callGroupAddRemove performs add/remove buckets operation for the indicated group
2102func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2103 if err := f.performGroupOperation(group); err != nil {
2104 st, _ := status.FromError(err)
2105 //ignore already exists error code
2106 if st.Code() != codes.AlreadyExists {
2107 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002108 }
2109 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002110 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002111}
2112
2113//findDiff compares group members and finds members which only exists in groups2
2114func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2115 var members []*openoltpb2.GroupMember
2116 for _, bucket := range group2.Members {
2117 if !f.contains(group1.Members, bucket) {
2118 // bucket does not exist and must be added
2119 members = append(members, bucket)
2120 }
2121 }
2122 return members
2123}
2124
2125//contains returns true if the members list contains the given member; false otherwise
2126func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2127 for _, groupMember := range members {
2128 if groupMember.InterfaceId == member.InterfaceId {
2129 return true
2130 }
2131 }
2132 return false
2133}
2134
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002135//performGroupOperation call performGroupOperation operation of openolt proto
2136func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002137 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2138 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2139 if err != nil {
2140 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2141 }
2142 return err
2143}
2144
2145//buildGroup build openoltpb2.Group from given group id and bucket list
2146func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2147 group := openoltpb2.Group{
2148 GroupId: groupID}
2149 // create members of the group
2150 if buckets != nil {
2151 for _, ofBucket := range buckets {
2152 member := f.buildMember(ofBucket)
2153 if member != nil && !f.contains(group.Members, member) {
2154 group.Members = append(group.Members, member)
2155 }
2156 }
2157 }
2158 return &group
2159}
2160
2161//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2162func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2163 var outPort uint32
2164 outPortFound := false
2165 for _, ofAction := range ofBucket.Actions {
2166 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2167 outPort = ofAction.GetOutput().Port
2168 outPortFound = true
2169 }
2170 }
2171
2172 if !outPortFound {
2173 log.Debugw("bucket skipped since no out port found in it",
2174 log.Fields{"ofBucket": ofBucket})
2175 return nil
2176 }
2177 interfaceID := IntfIDFromUniPortNum(outPort)
2178 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2179 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2180 member := openoltpb2.GroupMember{
2181 InterfaceId: interfaceID,
2182 InterfaceType: openoltpb2.GroupMember_PON,
2183 GemPortId: groupInfo.gemPortID,
2184 Priority: groupInfo.servicePriority,
2185 }
2186 //add member to the group
2187 return &member
2188 }
2189 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2190 log.Fields{"ofBucket": ofBucket})
2191 return nil
2192}
2193
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002194//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002195func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002196
2197 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302198 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002199 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302200 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302201 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302202 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002203
Manikkaraj kb1d51442019-07-23 10:41:02 -04002204 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002205 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002206 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2207 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2208 tpDownloadMsg,
2209 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2210 f.deviceHandler.deviceType,
2211 onuDevice.Type,
2212 onuDevice.Id,
2213 onuDevice.ProxyAddress.DeviceId, "")
2214 if sendErr != nil {
2215 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2216 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2217 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2218 return sendErr
2219 }
2220 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302221 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302222}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002223
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302224//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302225func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302226
2227 f.lockCache.Lock()
2228 defer f.lockCache.Unlock()
2229 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2230 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
npujarec5762e2020-01-01 14:08:48 +05302231 if err := f.resourceMgr.AddOnuInfo(ctx, intfID, onu); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302232 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2233 return
2234 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002235 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2236}
2237
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302238//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302239func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302240 f.lockCache.Lock()
2241 defer f.lockCache.Unlock()
2242 onugem := f.onuGemInfo[intfID]
2243 // update the gem to the local cache as well as to kv strore
2244 for idx, onu := range onugem {
2245 if onu.OnuID == onuID {
2246 // check if gem already exists , else update the cache and kvstore
2247 for _, gem := range onu.GemPorts {
2248 if gem == gemPort {
2249 log.Debugw("Gem already in cache, no need to update cache and kv store",
2250 log.Fields{"gem": gemPort})
2251 return
2252 }
2253 }
2254 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2255 f.onuGemInfo[intfID] = onugem
2256 }
2257 }
npujarec5762e2020-01-01 14:08:48 +05302258 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302259 if err != nil {
2260 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002261 return
2262 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002263}
2264
2265// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002266
2267//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2268func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302269
2270 f.lockCache.Lock()
2271 defer f.lockCache.Unlock()
2272
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002273 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 +05302274 // get onuid from the onugem info cache
2275 onugem := f.onuGemInfo[intfID]
2276 for _, onu := range onugem {
2277 for _, gem := range onu.GemPorts {
2278 if gem == gemPortID {
2279 return onu.OnuID, nil
2280 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002281 }
2282 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002283 return uint32(0), NewErrNotFound("onu-id", log.Fields{
2284 "serial-number": serialNumber,
2285 "interface-id": intfID,
2286 "gem-port-id": gemPortID},
2287 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002288}
2289
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002290//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302291func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002292 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002293 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002294 var err error
2295
2296 if packetIn.IntfType == "pon" {
2297 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002298 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002299 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2300 return logicalPortNum, err
2301 }
2302 if packetIn.PortNo != 0 {
2303 logicalPortNum = packetIn.PortNo
2304 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002305 uniID := uint32(0) // FIXME - multi-uni support
2306 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002307 }
2308 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302309 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002310 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002311 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002312 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002313 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2314 "logicalPortNum": logicalPortNum,
2315 "IntfType": packetIn.IntfType,
2316 "packet": hex.EncodeToString(packetIn.Pkt),
2317 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002318 return logicalPortNum, nil
2319}
2320
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002321//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302322func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002323 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002324 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302325
2326 f.lockCache.Lock()
2327 defer f.lockCache.Unlock()
2328 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2329
2330 gemPortID, ok := f.packetInGemPort[pktInkey]
2331 if ok {
2332 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2333 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002334 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302335 //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 +05302336 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302337 if err == nil {
2338 if gemPortID != 0 {
2339 f.packetInGemPort[pktInkey] = gemPortID
2340 log.Debugw("Found gem port from kv store and updating cache with gemport",
2341 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2342 return gemPortID, nil
2343 }
2344 }
2345 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2346 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002347}
2348
npujarec5762e2020-01-01 14:08:48 +05302349func installFlowOnAllGemports(ctx context.Context,
2350 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002351 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002352 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302353 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302354 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
David K. Bainbridge794735f2020-02-11 21:01:37 -08002355 classifier map[string]interface{}, action map[string]interface{}) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002356 args map[string]uint32,
2357 classifier map[string]interface{}, action map[string]interface{},
2358 logicalFlow *ofp.OfpFlowStats,
2359 gemPorts []uint32,
2360 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002361 vlanID ...uint32) {
2362 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
2363 for _, gemPortID := range gemPorts {
Manikkaraj kb1d51442019-07-23 10:41:02 -04002364 if FlowType == HsiaFlow || FlowType == DhcpFlow {
npujarec5762e2020-01-01 14:08:48 +05302365 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002366 } else if FlowType == EapolFlow {
npujarec5762e2020-01-01 14:08:48 +05302367 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 -04002368 } else {
2369 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2370 return
2371 }
2372 }
2373}
2374
David K. Bainbridge794735f2020-02-11 21:01:37 -08002375func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002376 log.Debug("Adding trap-dhcp-of-nni-flow")
2377 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002378 classifier[PacketTagType] = DoubleTag
2379 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002380 /* We manage flowId resource pool on per PON port basis.
2381 Since this situation is tricky, as a hack, we pass the NNI port
2382 index (network_intf_id) as PON port Index for the flowId resource
2383 pool. Also, there is no ONU Id available for trapping DHCP packets
2384 on NNI port, use onu_id as -1 (invalid)
2385 ****************** CAVEAT *******************
2386 This logic works if the NNI Port Id falls within the same valid
2387 range of PON Port Ids. If this doesn't work for some OLT Vendor
2388 we need to have a re-look at this.
2389 *********************************************
2390 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002391 onuID := -1
2392 uniID := -1
2393 gemPortID := -1
2394 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002395 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302396 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002397 return NewErrNotFound("nni-intreface-id", log.Fields{
2398 "classifier": classifier,
2399 "action": action},
2400 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302401 }
2402
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002403 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302404 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002405 log.Debug("Flow-exists-not-re-adding")
2406 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002407 }
npujarec5762e2020-01-01 14:08:48 +05302408 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002409 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002410 return NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
2411 "interface-id": networkInterfaceID,
2412 "onu-id": onuID,
2413 "uni-id": uniID,
2414 "gem-port-id": gemPortID,
2415 "cookie": flowStoreCookie},
2416 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002417 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002418 classifierProto, err := makeOpenOltClassifierField(classifier)
2419 if err != nil {
2420 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002421 }
2422 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002423 actionProto, err := makeOpenOltActionField(action)
2424 if err != nil {
2425 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002426 }
2427 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002428 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2429 OnuId: int32(onuID), // OnuId not required
2430 UniId: int32(uniID), // UniId not used
2431 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002432 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002433 AllocId: int32(allocID), // AllocId not used
2434 NetworkIntfId: int32(networkInterfaceID),
2435 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002436 Classifier: classifierProto,
2437 Action: actionProto,
2438 Priority: int32(logicalFlow.Priority),
2439 Cookie: logicalFlow.Cookie,
2440 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002441 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2442 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002443 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002444 log.Debug("DHCP trap on NNI flow added to device successfully")
2445 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2446 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2447 int32(onuID),
2448 int32(uniID),
2449 flowID, flowsToKVStore); err != nil {
2450 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2451 }
2452 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002453}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002454
Esin Karamanae41e2b2019-12-17 18:13:13 +00002455//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2456func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2457 var packetType string
2458 ovid, ivid := false, false
2459 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2460 vid := vlanID & VlanvIDMask
2461 if vid != ReservedVlan {
2462 ovid = true
2463 }
2464 }
2465 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2466 vid := uint32(metadata)
2467 if vid != ReservedVlan {
2468 ivid = true
2469 }
2470 }
2471 if ovid && ivid {
2472 packetType = DoubleTag
2473 } else if !ovid && !ivid {
2474 packetType = Untagged
2475 } else {
2476 packetType = SingleTag
2477 }
2478 return packetType
2479}
2480
2481//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002482func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002483 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2484 action := make(map[string]interface{})
2485 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2486 action[TrapToHost] = true
2487 /* We manage flowId resource pool on per PON port basis.
2488 Since this situation is tricky, as a hack, we pass the NNI port
2489 index (network_intf_id) as PON port Index for the flowId resource
2490 pool. Also, there is no ONU Id available for trapping packets
2491 on NNI port, use onu_id as -1 (invalid)
2492 ****************** CAVEAT *******************
2493 This logic works if the NNI Port Id falls within the same valid
2494 range of PON Port Ids. If this doesn't work for some OLT Vendor
2495 we need to have a re-look at this.
2496 *********************************************
2497 */
2498 onuID := -1
2499 uniID := -1
2500 gemPortID := -1
2501 allocID := -1
2502 networkInterfaceID, err := getNniIntfID(classifier, action)
2503 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002504 return NewErrNotFound("nni-interface-id", log.Fields{
2505 "classifier": classifier,
2506 "action": action},
2507 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002508 }
2509 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302510 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002511 log.Debug("igmp-flow-exists-not-re-adding")
2512 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002513 }
npujarec5762e2020-01-01 14:08:48 +05302514 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002515 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002516 return NewErrNotFound("igmp-flow-id", log.Fields{
2517 "interface-id": networkInterfaceID,
2518 "onu-id": onuID,
2519 "uni-id": uniID,
2520 "gem-port-id": gemPortID,
2521 "cookie": flowStoreCookie},
2522 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002523 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002524 classifierProto, err := makeOpenOltClassifierField(classifier)
2525 if err != nil {
2526 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002527 }
2528 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002529 actionProto, err := makeOpenOltActionField(action)
2530 if err != nil {
2531 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002532 }
2533 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2534 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2535 OnuId: int32(onuID), // OnuId not required
2536 UniId: int32(uniID), // UniId not used
2537 FlowId: flowID,
2538 FlowType: Downstream,
2539 AllocId: int32(allocID), // AllocId not used
2540 NetworkIntfId: int32(networkInterfaceID),
2541 GemportId: int32(gemPortID), // GemportId not used
2542 Classifier: classifierProto,
2543 Action: actionProto,
2544 Priority: int32(logicalFlow.Priority),
2545 Cookie: logicalFlow.Cookie,
2546 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002547 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2548 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002549 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002550 log.Debug("IGMP Trap on NNI flow added to device successfully")
2551 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2552 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2553 int32(onuID),
2554 int32(uniID),
2555 flowID, flowsToKVStore); err != nil {
2556 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2557 }
2558 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002559}
2560
salmansiddiqui7ac62132019-08-22 03:58:50 +00002561func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2562 if MeterID == 0 { // This should never happen
David K. Bainbridge794735f2020-02-11 21:01:37 -08002563 return "", NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002564 }
2565 if Dir == tp_pb.Direction_UPSTREAM {
2566 return "upstream", nil
2567 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2568 return "downstream", nil
2569 }
2570 return "", nil
2571}
2572
npujarec5762e2020-01-01 14:08:48 +05302573func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002574 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2575 TpID uint32, uni string) {
2576 var gemPort uint32
2577 intfID := args[IntfID]
2578 onuID := args[OnuID]
2579 uniID := args[UniID]
2580 portNo := args[PortNo]
2581 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002582 if ipProto, ok := classifierInfo[IPProto]; ok {
2583 if ipProto.(uint32) == IPProtoDhcp {
2584 log.Info("Adding DHCP flow")
2585 if pcp, ok := classifierInfo[VlanPcp]; ok {
2586 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2587 tp_pb.Direction_UPSTREAM,
2588 pcp.(uint32))
2589 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302590 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002591 } else {
2592 //Adding DHCP upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302593 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002594 }
2595
2596 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002597 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2598 if pcp, ok := classifierInfo[VlanPcp]; ok {
2599 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2600 tp_pb.Direction_UPSTREAM,
2601 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302602 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002603 } else {
2604 //Adding IGMP upstream flow to all gem ports
npujarec5762e2020-01-01 14:08:48 +05302605 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002606 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002607 } else {
2608 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2609 return
2610 }
2611 } else if ethType, ok := classifierInfo[EthType]; ok {
2612 if ethType.(uint32) == EapEthType {
2613 log.Info("Adding EAPOL flow")
2614 var vlanID uint32
2615 if val, ok := classifierInfo[VlanVid]; ok {
2616 vlanID = (val.(uint32)) & VlanvIDMask
2617 } else {
2618 vlanID = DefaultMgmtVlan
2619 }
2620 if pcp, ok := classifierInfo[VlanPcp]; ok {
2621 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2622 tp_pb.Direction_UPSTREAM,
2623 pcp.(uint32))
2624
npujarec5762e2020-01-01 14:08:48 +05302625 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, flow, allocID, gemPort, vlanID, classifierInfo, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002626 } else {
npujarec5762e2020-01-01 14:08:48 +05302627 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002628 }
2629 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002630 } else if _, ok := actionInfo[PushVlan]; ok {
2631 log.Info("Adding upstream data rule")
2632 if pcp, ok := classifierInfo[VlanPcp]; ok {
2633 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2634 tp_pb.Direction_UPSTREAM,
2635 pcp.(uint32))
2636 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302637 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002638 } else {
2639 //Adding HSIA upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302640 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002641 }
2642 } else if _, ok := actionInfo[PopVlan]; ok {
2643 log.Info("Adding Downstream data rule")
2644 if pcp, ok := classifierInfo[VlanPcp]; ok {
2645 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002646 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002647 pcp.(uint32))
2648 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302649 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002650 } else {
2651 //Adding HSIA downstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302652 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002653 }
2654 } else {
2655 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2656 return
2657 }
2658 // Send Techprofile download event to child device in go routine as it takes time
2659 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2660}
2661
Gamze Abakafee36392019-10-03 11:17:24 +00002662func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2663 flowIDList := f.flowsUsedByGemPort[gemPK]
2664 if len(flowIDList) > 1 {
2665 return true
2666 }
2667 return false
2668}
2669
npujarec5762e2020-01-01 14:08:48 +05302670func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2671 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002672 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2673 for _, currentGemPort := range currentGemPorts {
2674 for _, tpGemPort := range tpGemPorts {
2675 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2676 return true, currentGemPort
2677 }
2678 }
2679 }
Girish Gowdra54934262019-11-13 14:19:55 +05302680 if tpInst.InstanceCtrl.Onu == "single-instance" {
2681 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302682 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2683 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302684
2685 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2686 // still be used on other uni ports.
2687 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2688 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302689 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302690 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302691 for i := 0; i < len(tpInstances); i++ {
2692 tpI := tpInstances[i]
2693 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302694 for _, tpGemPort := range tpGemPorts {
2695 if tpGemPort.GemportID != gemPortID {
2696 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2697 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302698 }
2699 }
2700 }
2701 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302702 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002703 return false, 0
2704}
2705
salmansiddiqui7ac62132019-08-22 03:58:50 +00002706func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002707 for _, field := range flows.GetOfbFields(flow) {
2708 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002709 classifierInfo[EthType] = field.GetEthType()
2710 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002711 } else if field.Type == flows.ETH_DST {
2712 classifierInfo[EthDst] = field.GetEthDst()
2713 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002714 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002715 classifierInfo[IPProto] = field.GetIpProto()
2716 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002717 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002718 classifierInfo[InPort] = field.GetPort()
2719 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002720 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302721 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002722 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002723 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002724 classifierInfo[VlanPcp] = field.GetVlanPcp()
2725 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002726 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002727 classifierInfo[UDPDst] = field.GetUdpDst()
2728 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002729 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002730 classifierInfo[UDPSrc] = field.GetUdpSrc()
2731 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002732 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002733 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2734 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002735 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002736 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2737 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002738 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002739 classifierInfo[Metadata] = field.GetTableMetadata()
2740 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002741 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002742 classifierInfo[TunnelID] = field.GetTunnelId()
2743 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2744 } else {
2745 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2746 return
2747 }
2748 }
2749}
2750
2751func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002752 for _, action := range flows.GetActions(flow) {
2753 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002754 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002755 actionInfo[Output] = out.GetPort()
2756 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002757 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002758 return NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002759 }
Scott Baker355d1742019-10-24 10:57:52 -07002760 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002761 actionInfo[PopVlan] = true
2762 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002763 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002764 if out := action.GetPush(); out != nil {
2765 if tpid := out.GetEthertype(); tpid != 0x8100 {
2766 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2767 } else {
2768 actionInfo[PushVlan] = true
2769 actionInfo[TPID] = tpid
2770 log.Debugw("action-type-push-vlan",
2771 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2772 }
2773 }
Scott Baker355d1742019-10-24 10:57:52 -07002774 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002775 if out := action.GetSetField(); out != nil {
2776 if field := out.GetField(); field != nil {
2777 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002778 return NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002779 }
2780 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002781 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002782 }
2783 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002784 } else if action.Type == flows.GROUP {
2785 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002786 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002787 return NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002788 }
2789 }
2790 return nil
2791}
2792
Esin Karamanccb714b2019-11-29 15:02:06 +00002793func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2794 if ofbField := field.GetOfbField(); ofbField != nil {
2795 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2796 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2797 actionInfo[VlanVid] = vlan & 0xfff
2798 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2799 } else {
2800 log.Error("No Invalid vlan id in set vlan-vid action")
2801 }
2802 } else {
2803 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2804 }
2805 }
2806}
2807
2808func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2809 if action.GetGroup() == nil {
2810 log.Warn("No group entry found in the group action")
2811 } else {
2812 actionInfo[GroupID] = action.GetGroup().GroupId
2813 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2814 }
2815}
2816
salmansiddiqui7ac62132019-08-22 03:58:50 +00002817func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002818 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002819 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2820 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2821 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002822 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002823 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002824 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 +00002825 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002826 return NewErrNotFound("child-in-port", log.Fields{
2827 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2828 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002829 }
2830 }
2831 } else {
2832 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2833 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002834 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002835 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002836 actionInfo[Output] = uniPort
2837 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 +00002838 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002839 return NewErrNotFound("out-port", log.Fields{
2840 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2841 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002842 }
2843 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2844 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002845 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002846 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002847 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2848 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002849 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002850 return NewErrNotFound("nni-port", log.Fields{
2851 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2852 "in-port": classifierInfo[InPort].(uint32),
2853 "out-port": actionInfo[Output].(uint32),
2854 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002855 }
2856 }
2857 }
2858 return nil
2859}
Gamze Abakafee36392019-10-03 11:17:24 +00002860
Chaitrashree G S90a17952019-11-14 21:51:21 -05002861func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002862 /* Metadata 8 bytes:
2863 Most Significant 2 Bytes = Inner VLAN
2864 Next 2 Bytes = Tech Profile ID(TPID)
2865 Least Significant 4 Bytes = Port ID
2866 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2867 subscriber related flows.
2868 */
2869 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2870 if metadata == 0 {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002871 return 0, NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002872 }
2873 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002874 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002875}
2876
2877func appendUnique(slice []uint32, item uint32) []uint32 {
2878 for _, sliceElement := range slice {
2879 if sliceElement == item {
2880 return slice
2881 }
2882 }
2883 return append(slice, item)
2884}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302885
2886// getNniIntfID gets nni intf id from the flow classifier/action
2887func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2888
2889 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2890 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002891 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2892 if err != nil {
2893 log.Debugw("invalid-action-port-number",
2894 log.Fields{
2895 "port-number": action[Output].(uint32),
2896 "error": err})
2897 return uint32(0), err
2898 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302899 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2900 return intfID, nil
2901 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002902 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2903 if err != nil {
2904 log.Debugw("invalid-classifier-port-number",
2905 log.Fields{
2906 "port-number": action[Output].(uint32),
2907 "error": err})
2908 return uint32(0), err
2909 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302910 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2911 return intfID, nil
2912 }
2913 return uint32(0), nil
2914}
2915
2916// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302917func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302918 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2919
2920 f.lockCache.Lock()
2921 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002922 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302923 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002924 if lookupGemPort == gemPort {
2925 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2926 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2927 return
2928 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302929 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002930 f.packetInGemPort[pktInkey] = gemPort
2931
npujarec5762e2020-01-01 14:08:48 +05302932 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002933 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 +05302934 return
2935}
2936
2937// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302938func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302939
2940 f.lockCache.Lock()
2941 defer f.lockCache.Unlock()
2942 onugem := f.onuGemInfo[intfID]
2943 for idx, onu := range onugem {
2944 if onu.OnuID == onuID {
2945 for _, uni := range onu.UniPorts {
2946 if uni == portNum {
2947 log.Debugw("uni already in cache, no need to update cache and kv store",
2948 log.Fields{"uni": portNum})
2949 return
2950 }
2951 }
2952 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2953 f.onuGemInfo[intfID] = onugem
2954 }
2955 }
npujarec5762e2020-01-01 14:08:48 +05302956 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302957}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302958
npujarec5762e2020-01-01 14:08:48 +05302959func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2960 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302961 if err != nil {
2962 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2963 return
2964 }
2965 for gem, FlowIDs := range flowIDsList {
2966 gemPK := gemPortKey{intf, uint32(gem)}
2967 f.flowsUsedByGemPort[gemPK] = FlowIDs
2968 }
2969 return
2970}
Esin Karamanccb714b2019-11-29 15:02:06 +00002971
2972//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2973//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302974func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2975 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002976 if err != nil {
2977 log.Error("Failed to get pon interface to multicast queue map")
2978 return
2979 }
2980 for intf, queueInfo := range storedMulticastQueueMap {
2981 q := queueInfoBrief{
2982 gemPortID: queueInfo[0],
2983 servicePriority: queueInfo[1],
2984 }
2985 f.interfaceToMcastQueueMap[intf] = &q
2986 }
2987}
2988
2989//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
2990//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
2991//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05302992func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
2993 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00002994 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002995 return nil, false, NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002996 }
2997 if exists {
2998 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
2999 }
3000 return nil, exists, nil
3001}
3002
3003func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3004 groupDesc := ofp.OfpGroupDesc{
3005 Type: ofp.OfpGroupType_OFPGT_ALL,
3006 GroupId: groupID,
3007 }
3008 groupEntry := ofp.OfpGroupEntry{
3009 Desc: &groupDesc,
3010 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003011 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003012 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003013 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003014 bucket := ofp.OfpBucket{
3015 Actions: acts,
3016 }
3017 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003018 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003019 return &groupEntry
3020}