blob: 3ed340f6ff6ce5fa1cb1fcb3182ca09a74714662 [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
Scott Bakerdbd960e2020-02-28 08:57:51 -080017//Package core provides the utility for olt devices, flows and statistics
18package core
manikkaraj kbf256be2019-03-25 00:13:48 +053019
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"
Girish Gowdrafae935c2020-02-17 19:21:44 +053027 "strings"
William Kurkian740a09c2019-10-23 17:07:38 -040028 "sync"
Girish Gowdra3d633032019-12-10 16:37:05 +053029 "time"
Manikkaraj kb1d51442019-07-23 10:41:02 -040030
Esin Karamanccb714b2019-11-29 15:02:06 +000031 "github.com/opencord/voltha-lib-go/v3/pkg/flows"
32 "github.com/opencord/voltha-lib-go/v3/pkg/log"
33 tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
Scott Bakerdbd960e2020-02-28 08:57:51 -080034 rsrcMgr "github.com/opencord/voltha-openolt-adapter/internal/pkg/resourcemanager"
Esin Karamanccb714b2019-11-29 15:02:06 +000035 "github.com/opencord/voltha-protos/v3/go/common"
36 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
37 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
38 openoltpb2 "github.com/opencord/voltha-protos/v3/go/openolt"
39 tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
40 "github.com/opencord/voltha-protos/v3/go/voltha"
Chaitrashree G S579fe732019-08-20 20:50:47 -040041
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040042 //deepcopy "github.com/getlantern/deepcopy"
Girish Gowdra3d633032019-12-10 16:37:05 +053043 "github.com/EagleChen/mapmutex"
Daniele Rossi22db98e2019-07-11 11:50:00 +000044 "google.golang.org/grpc/codes"
45 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053046)
47
48const (
49 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053050
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070051 //HsiaFlow flow category
52 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053053
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070054 //EapolFlow flow category
55 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053056
Manikkaraj kb1d51442019-07-23 10:41:02 -040057 //DhcpFlow flow category
58 DhcpFlow = "DHCP_FLOW"
59
Esin Karamanccb714b2019-11-29 15:02:06 +000060 //MulticastFlow flow category
61 MulticastFlow = "MULTICAST_FLOW"
62
Esin Karamanae41e2b2019-12-17 18:13:13 +000063 //IgmpFlow flow category
64 IgmpFlow = "IGMP_FLOW"
65
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070066 //IPProtoDhcp flow category
67 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053068
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070069 //IPProtoIgmp flow category
70 IPProtoIgmp = 2
71
72 //EapEthType eapethtype value
73 EapEthType = 0x888e
74 //LldpEthType lldp ethtype value
75 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000076 //IPv4EthType IPv4 ethernet type value
77 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070078
79 //IgmpProto proto value
80 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053081
Andrea Campanella7acc0b92020-02-14 09:20:49 +010082 //ReservedVlan Transparent Vlan (Masked Vlan, VLAN_ANY in ONOS Flows)
83 ReservedVlan = 4096
Harsh Awasthiea45af72019-08-26 02:39:00 -040084
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070085 //DefaultMgmtVlan default vlan value
86 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053087
manikkaraj kbf256be2019-03-25 00:13:48 +053088 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070089
David K. Bainbridge82efc492019-09-04 09:57:11 -070090 //Upstream constant
91 Upstream = "upstream"
92 //Downstream constant
93 Downstream = "downstream"
Esin Karamanccb714b2019-11-29 15:02:06 +000094 //Multicast constant
95 Multicast = "multicast"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070096 //PacketTagType constant
97 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -070098 //Untagged constant
99 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700100 //SingleTag constant
101 SingleTag = "single_tag"
102 //DoubleTag constant
103 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530104
105 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700106
107 //EthType constant
108 EthType = "eth_type"
Esin Karamanccb714b2019-11-29 15:02:06 +0000109 //EthDst constant
110 EthDst = "eth_dst"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700111 //TPID constant
112 TPID = "tpid"
113 //IPProto constant
114 IPProto = "ip_proto"
115 //InPort constant
116 InPort = "in_port"
117 //VlanVid constant
118 VlanVid = "vlan_vid"
119 //VlanPcp constant
120 VlanPcp = "vlan_pcp"
121
122 //UDPDst constant
123 UDPDst = "udp_dst"
124 //UDPSrc constant
125 UDPSrc = "udp_src"
126 //Ipv4Dst constant
127 Ipv4Dst = "ipv4_dst"
128 //Ipv4Src constant
129 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700130 //Metadata constant
131 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700132 //TunnelID constant
133 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700134 //Output constant
135 Output = "output"
Esin Karamanccb714b2019-11-29 15:02:06 +0000136 //GroupID constant
137 GroupID = "group_id"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700138 // Actions
139
140 //PopVlan constant
141 PopVlan = "pop_vlan"
142 //PushVlan constant
143 PushVlan = "push_vlan"
144 //TrapToHost constant
145 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400146 //MaxMeterBand constant
147 MaxMeterBand = 2
148 //VlanPCPMask contant
149 VlanPCPMask = 0xFF
150 //VlanvIDMask constant
151 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000152 //IntfID constant
153 IntfID = "intfId"
154 //OnuID constant
155 OnuID = "onuId"
156 //UniID constant
157 UniID = "uniId"
158 //PortNo constant
159 PortNo = "portNo"
160 //AllocID constant
161 AllocID = "allocId"
Esin Karamanccb714b2019-11-29 15:02:06 +0000162
163 //NoneOnuID constant
164 NoneOnuID = -1
165 //NoneUniID constant
166 NoneUniID = -1
167 //NoneGemPortID constant
168 NoneGemPortID = -1
Girish Gowdrafae935c2020-02-17 19:21:44 +0530169
170 // BinaryStringPrefix is binary string prefix
171 BinaryStringPrefix = "0b"
172 // BinaryBit1 is binary bit 1 expressed as a character
173 BinaryBit1 = '1'
manikkaraj kbf256be2019-03-25 00:13:48 +0530174)
175
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400176type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700177 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400178 gemPort uint32
179}
180
Girish Gowdra3d633032019-12-10 16:37:05 +0530181type pendingFlowDeleteKey struct {
182 intfID uint32
183 onuID uint32
184 uniID uint32
185}
186
187type tpLockKey struct {
188 intfID uint32
189 onuID uint32
190 uniID uint32
191}
192
Gamze Abakafee36392019-10-03 11:17:24 +0000193type schedQueue struct {
194 direction tp_pb.Direction
195 intfID uint32
196 onuID uint32
197 uniID uint32
198 tpID uint32
199 uniPort uint32
200 tpInst *tp.TechProfile
201 meterID uint32
202 flowMetadata *voltha.FlowMetadata
203}
204
Esin Karamanccb714b2019-11-29 15:02:06 +0000205type queueInfoBrief struct {
206 gemPortID uint32
207 servicePriority uint32
208}
209
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700210//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530211type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000212 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000213 deviceHandler *DeviceHandler
214 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000215 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530216 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
217 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
218 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
219 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530220 pendingFlowDelete sync.Map
221 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
Esin Karamanccb714b2019-11-29 15:02:06 +0000222 perUserFlowHandleLock *mapmutex.Mutex
223 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 +0530224}
225
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700226//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
npujarec5762e2020-01-01 14:08:48 +0530227func NewFlowManager(ctx context.Context, dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530228 log.Info("Initializing flow manager")
229 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530230 var err error
231 var idx uint32
232
manikkaraj kbf256be2019-03-25 00:13:48 +0530233 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530234 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000235 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530236 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530237 log.Error("Error while populating tech profile mgr\n")
238 return nil
239 }
William Kurkian740a09c2019-10-23 17:07:38 -0400240 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530241 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
242 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
243 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
244 ponPorts := rMgr.DevInfo.GetPonPorts()
245 //Load the onugem info cache from kv store on flowmanager start
246 for idx = 0; idx < ponPorts; idx++ {
npujarec5762e2020-01-01 14:08:48 +0530247 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(ctx, idx); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530248 log.Error("Failed to load onu gem info cache")
249 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530250 //Load flowID list per gem map per interface from the kvstore.
npujarec5762e2020-01-01 14:08:48 +0530251 flowMgr.loadFlowIDlistForGem(ctx, idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530252 }
253 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530254 flowMgr.pendingFlowDelete = sync.Map{}
255 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
Esin Karamanccb714b2019-11-29 15:02:06 +0000256 flowMgr.interfaceToMcastQueueMap = make(map[uint32]*queueInfoBrief)
257 //load interface to multicast queue map from kv store
npujarec5762e2020-01-01 14:08:48 +0530258 flowMgr.loadInterfaceToMulticastQueueMap(ctx)
manikkaraj kbf256be2019-03-25 00:13:48 +0530259 log.Info("Initialization of flow manager success!!")
260 return &flowMgr
261}
262
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700263func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700264 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400265 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700266 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700267 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400268 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700269 return uint64(flowID), nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000270 } else if direction == Multicast {
271 log.Debug("multicast flow, shifting id")
272 return 0x2<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400273 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800274 return 0, NewErrInvalidValue(log.Fields{"direction": direction}, nil).Log()
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400275 }
276}
277
npujarec5762e2020-01-01 14:08:48 +0530278func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400279 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700280 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000281 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
282 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
283 if !ok {
284 flowIDList = []uint32{deviceFlow.FlowId}
285 }
286 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
287 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530288 // update the flowids for a gem to the KVstore
npujarec5762e2020-01-01 14:08:48 +0530289 f.resourceMgr.UpdateFlowIDsForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400290}
291
npujarec5762e2020-01-01 14:08:48 +0530292func (f *OpenOltFlowMgr) divideAndAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000293 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
294 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000295 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530296 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400297 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530298
Manikkaraj kb1d51442019-07-23 10:41:02 -0400299 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000300 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400301 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
302 // is because the flow is an NNI flow and there would be no onu resources associated with it
303 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400304 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400305 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530306 return
307 }
308
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530309 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400310 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530311
312 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
313 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
npujarec5762e2020-01-01 14:08:48 +0530314 allocID, gemPorts, TpInst = f.createTcontGemports(ctx, intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +0530315 if allocID == 0 || gemPorts == nil || TpInst == nil {
316 log.Error("alloc-id-gem-ports-tp-unavailable")
317 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
318 return
319 }
320 args := make(map[string]uint32)
321 args[IntfID] = intfID
322 args[OnuID] = onuID
323 args[UniID] = uniID
324 args[PortNo] = portNo
325 args[AllocID] = allocID
326
327 /* Flows can be added specific to gemport if p-bits are received.
328 * If no pbit mentioned then adding flows for all gemports
329 */
npujarec5762e2020-01-01 14:08:48 +0530330 f.checkAndAddFlow(ctx, args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
Girish Gowdra3d633032019-12-10 16:37:05 +0530331 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
332 } else {
333 log.Errorw("failed to acquire per user flow handle lock",
334 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400335 return
336 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530337}
338
salmansiddiqui7ac62132019-08-22 03:58:50 +0000339// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530340func (f *OpenOltFlowMgr) CreateSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400341
Gamze Abakafee36392019-10-03 11:17:24 +0000342 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
343 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
344 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400345
Gamze Abakafee36392019-10-03 11:17:24 +0000346 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000347 if err != nil {
348 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400349 }
350
351 /* Lets make a simple assumption that if the meter-id is present on the KV store,
352 * then the scheduler and queues configuration is applied on the OLT device
353 * in the given direction.
354 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000355
Manikkaraj kb1d51442019-07-23 10:41:02 -0400356 var SchedCfg *tp_pb.SchedulerConfig
npujarec5762e2020-01-01 14:08:48 +0530357 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400358 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000359 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 -0400360 return err
361 }
362 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000363 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400364 log.Debug("Scheduler already created for upstream")
365 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400366 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800367 return NewErrInvalidValue(log.Fields{
368 "unsupported": "meter-id",
369 "kv-store-meter-id": KvStoreMeter.MeterId,
370 "meter-id-in-flow": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400371 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000372
Gamze Abakafee36392019-10-03 11:17:24 +0000373 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000374
Gamze Abakafee36392019-10-03 11:17:24 +0000375 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000376 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000377 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000378 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400379 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000380
381 if err != nil {
382 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
383 return err
384 }
385
Manikkaraj kb1d51442019-07-23 10:41:02 -0400386 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000387 if sq.flowMetadata != nil {
388 for _, meter := range sq.flowMetadata.Meters {
389 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400390 meterConfig = meter
391 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
392 break
393 }
394 }
395 } else {
396 log.Error("Flow-metadata-is-not-present-in-flow")
397 }
398 if meterConfig == nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800399 return NewErrNotFound("meterbands", log.Fields{
400 "reason": "Could-not-get-meterbands-from-flowMetadata",
401 "flow-metadata": sq.flowMetadata,
402 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400403 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000404 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800405 return NewErrInvalidValue(log.Fields{
406 "reason": "Invalid-number-of-bands-in-meter",
407 "meterband-count": len(meterConfig.Bands),
408 "metabands": meterConfig.Bands,
409 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400410 }
411 cir := meterConfig.Bands[0].Rate
412 cbs := meterConfig.Bands[0].BurstSize
413 eir := meterConfig.Bands[1].Rate
414 ebs := meterConfig.Bands[1].BurstSize
415 pir := cir + eir
416 pbs := cbs + ebs
417 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
418
Gamze Abakafee36392019-10-03 11:17:24 +0000419 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400420
npujarec5762e2020-01-01 14:08:48 +0530421 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000422 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 -0400423 return err
424 }
425
salmansiddiqui7ac62132019-08-22 03:58:50 +0000426 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400427 * store the meter id on the KV store, for further reference.
428 */
npujarec5762e2020-01-01 14:08:48 +0530429 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 +0000430 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400431 return err
432 }
433 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
434 "Meter": meterConfig})
435 return nil
436}
437
npujarec5762e2020-01-01 14:08:48 +0530438func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000439
440 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
441
442 if err != nil {
443 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
444 return err
445 }
446
447 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530448 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000449 IntfId: sq.intfID, OnuId: sq.onuID,
450 UniId: sq.uniID, PortNo: sq.uniPort,
451 TrafficScheds: TrafficSched}); err != nil {
452 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
453 return err
454 }
455
456 // On receiving the CreateTrafficQueues request, the driver should create corresponding
457 // downstream queues.
458 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530459 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000460 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
461 UniId: sq.uniID, PortNo: sq.uniPort,
462 TrafficQueues: trafficQueues}); err != nil {
463 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
464 return err
465 }
466
Esin Karamanccb714b2019-11-29 15:02:06 +0000467 if sq.direction == tp_pb.Direction_DOWNSTREAM {
468 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
469 if len(multicastTrafficQueues) > 0 {
470 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
471 //assumed that there is only one queue per PON for the multicast service
472 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
473 //just put it in interfaceToMcastQueueMap to use for building group members
474 multicastQueuePerPonPort := multicastTrafficQueues[0]
475 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
476 gemPortID: multicastQueuePerPonPort.GemportId,
477 servicePriority: multicastQueuePerPonPort.Priority,
478 }
479 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530480 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000481 multicastQueuePerPonPort.GemportId,
482 multicastQueuePerPonPort.Priority)
483 }
484 }
485 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000486 return nil
487}
488
salmansiddiqui7ac62132019-08-22 03:58:50 +0000489// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530490func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400491
492 var Direction string
493 var SchedCfg *tp_pb.SchedulerConfig
494 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000495 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
496 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
497 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000498 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400499 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000500 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000501 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400502 Direction = "downstream"
503 }
504
Girish Kumar8f73fe02019-12-09 13:19:37 +0000505 if err != nil {
506 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
507 return err
508 }
509
npujarec5762e2020-01-01 14:08:48 +0530510 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400511 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000512 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400513 return err
514 }
515 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000516 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 -0400517 return nil
518 }
519 cir := KVStoreMeter.Bands[0].Rate
520 cbs := KVStoreMeter.Bands[0].BurstSize
521 eir := KVStoreMeter.Bands[1].Rate
522 ebs := KVStoreMeter.Bands[1].BurstSize
523 pir := cir + eir
524 pbs := cbs + ebs
525
526 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
527
Gamze Abakafee36392019-10-03 11:17:24 +0000528 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000529
530 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
531 if err != nil {
532 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
533 return err
534 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400535
npujarec5762e2020-01-01 14:08:48 +0530536 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000537 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
538 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400539 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000540 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400541 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400542 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000543 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530544 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000545 IntfId: sq.intfID, OnuId: sq.onuID,
546 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400547 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000548 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400549 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400550 }
551
salmansiddiqui7ac62132019-08-22 03:58:50 +0000552 log.Debug("Removed traffic schedulers successfully")
553
554 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400555 * delete the meter id on the KV store.
556 */
npujarec5762e2020-01-01 14:08:48 +0530557 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400558 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000559 log.Errorf("Failed to remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000560 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400561 }
562 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
563 return err
564}
565
Gamze Abakafee36392019-10-03 11:17:24 +0000566// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530567func (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 +0000568 var allocIDs []uint32
569 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530570 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530571 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000572 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000573
npujarec5762e2020-01-01 14:08:48 +0530574 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
575 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400576
577 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530578
579 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
580
Manikkaraj kb1d51442019-07-23 10:41:02 -0400581 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530582 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000583 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530584 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530585 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000586 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530587 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000588 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000589 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530590 }
npujarec5762e2020-01-01 14:08:48 +0530591 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530592 } else {
593 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530594 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530595 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400596 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000597 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
598 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530599 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400600 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000601 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400602 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530603 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400604 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000605 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
606 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530607 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400608 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000609 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400610 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530611 }
Gamze Abakafee36392019-10-03 11:17:24 +0000612
613 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000614 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000615 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400616 }
Gamze Abakafee36392019-10-03 11:17:24 +0000617
Girish Gowdra3d633032019-12-10 16:37:05 +0530618 if tpInstanceExists {
619 return allocID, gemPortIDs, techProfileInstance
620 }
621
622 allocIDs = appendUnique(allocIDs, allocID)
623 for _, gemPortID := range gemPortIDs {
624 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
625 }
626
Gamze Abakafee36392019-10-03 11:17:24 +0000627 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530628 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530629 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000630 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530631}
632
npujarec5762e2020-01-01 14:08:48 +0530633func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530634
635 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700636 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530637 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530638 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530639 log.Error("Errow while uploading allocID to KV store")
640 }
npujarec5762e2020-01-01 14:08:48 +0530641 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530642 log.Error("Errow while uploading GEMports to KV store")
643 }
npujarec5762e2020-01-01 14:08:48 +0530644 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530645 log.Error("Errow while uploading gemtopon map to KV store")
646 }
647 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400648 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530649 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400650 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530651}
652
653func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000654 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530655 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000656 for _, intfID := range techRange.IntfIds {
657 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400658 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000659 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530660 }
661 }
662 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400663 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800664 return NewErrInvalidValue(log.Fields{
665 "reason": "TP count does not match number of PON ports",
666 "tech-profile-count": tpCount,
667 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530668 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400669 log.Infow("Populated techprofile for ponports successfully",
670 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530671 return nil
672}
673
npujarec5762e2020-01-01 14:08:48 +0530674func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530675 portNo uint32, uplinkClassifier map[string]interface{},
676 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800677 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700678 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530679 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800680 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700681 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530682 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530683}
684
npujarec5762e2020-01-01 14:08:48 +0530685func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530686 portNo uint32, downlinkClassifier map[string]interface{},
687 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800688 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700689 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530690 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
691 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400692 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
693 if vlan, exists := downlinkClassifier[VlanVid]; exists {
694 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700695 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400696 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
697 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800698 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400699 }
700 }
701 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530702 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400703
Manikkaraj k884c1242019-04-11 16:26:42 +0530704 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700705 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400706 // vlan_vid is a uint32. must be type asserted as such or conversion fails
707 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530708 if ok {
709 downlinkAction[VlanVid] = dlClVid & 0xfff
710 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800711 return NewErrInvalidValue(log.Fields{
712 "reason": "failed to convert VLANID classifier",
713 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530714 }
715
David K. Bainbridge794735f2020-02-11 21:01:37 -0800716 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700717 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530718}
719
npujarec5762e2020-01-01 14:08:48 +0530720func (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 +0530721 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800722 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530723 /* One of the OLT platform (Broadcom BAL) requires that symmetric
724 flows require the same flow_id to be used across UL and DL.
725 Since HSIA flow is the only symmetric flow currently, we need to
726 re-use the flow_id across both direction. The 'flow_category'
727 takes priority over flow_cookie to find any available HSIA_FLOW
728 id for the ONU.
729 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700730 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
731 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530732 "logicalFlow": *logicalFlow})
Girish Gowdrafae935c2020-02-17 19:21:44 +0530733 var vlanPbit uint32 = 0xff // means no pbit
Manikkaraj kb1d51442019-07-23 10:41:02 -0400734 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000735 vlanPbit = classifier[VlanPcp].(uint32)
736 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800737 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +0530738 log.Debugw("pbit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400739 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700740 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530741 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800742 log.Debug("flow-already-exists")
743 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530744 }
npujarec5762e2020-01-01 14:08:48 +0530745 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530746 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800747 return NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530748 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800749 classifierProto, err := makeOpenOltClassifierField(classifier)
750 if err != nil {
751 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530752 }
753 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800754 actionProto, err := makeOpenOltActionField(action)
755 if err != nil {
756 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530757 }
758 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800759 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530760 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800761 return NewErrNotFound("nni-interface-id",
762 log.Fields{
763 "classifier": classifier,
764 "action": action,
765 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530766 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700767 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
768 OnuId: int32(onuID),
769 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000770 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530771 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700772 AllocId: int32(allocID),
773 NetworkIntfId: int32(networkIntfID),
774 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530775 Classifier: classifierProto,
776 Action: actionProto,
777 Priority: int32(logicalFlow.Priority),
778 Cookie: logicalFlow.Cookie,
779 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800780 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
781 return NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530782 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800783 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
784 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
785 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
786 flow.OnuId,
787 flow.UniId,
788 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
789 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
790 }
791 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530792}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000793
David K. Bainbridge794735f2020-02-11 21:01:37 -0800794func (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 +0530795
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530796 networkIntfID, err := getNniIntfID(classifier, action)
797 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800798 return NewErrNotFound("nni-interface-id", log.Fields{
799 "classifier": classifier,
800 "action": action},
801 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530802 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530803
804 // Clear the action map
805 for k := range action {
806 delete(action, k)
807 }
808
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700809 action[TrapToHost] = true
810 classifier[UDPSrc] = uint32(68)
811 classifier[UDPDst] = uint32(67)
812 classifier[PacketTagType] = SingleTag
813 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530814
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700815 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530816 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530817 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800818 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530819 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530820
David K. Bainbridge794735f2020-02-11 21:01:37 -0800821 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 +0530822
823 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800824 return NewErrNotFound("flow", log.Fields{
825 "interface-id": intfID,
826 "gem-port": gemPortID,
827 "cookie": flowStoreCookie},
828 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530829 }
830
831 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
832
David K. Bainbridge794735f2020-02-11 21:01:37 -0800833 classifierProto, err := makeOpenOltClassifierField(classifier)
834 if err != nil {
835 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530836 }
837 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800838 actionProto, err := makeOpenOltActionField(action)
839 if err != nil {
840 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530841 }
842
David K. Bainbridge794735f2020-02-11 21:01:37 -0800843 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700844 OnuId: int32(onuID),
845 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530846 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700847 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700848 AllocId: int32(allocID),
849 NetworkIntfId: int32(networkIntfID),
850 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530851 Classifier: classifierProto,
852 Action: actionProto,
853 Priority: int32(logicalFlow.Priority),
854 Cookie: logicalFlow.Cookie,
855 PortNo: portNo}
856
David K. Bainbridge794735f2020-02-11 21:01:37 -0800857 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
858 return NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
859 }
860 log.Debug("DHCP UL flow added to device successfully")
861 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
862 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
863 dhcpFlow.OnuId,
864 dhcpFlow.UniId,
865 dhcpFlow.FlowId, flowsToKVStore); err != nil {
866 return NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530867 }
868
David K. Bainbridge794735f2020-02-11 21:01:37 -0800869 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530870}
871
Esin Karamanae41e2b2019-12-17 18:13:13 +0000872//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530873func (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 -0800874 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
875 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000876}
877
878//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530879func (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 -0800880 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000881
882 networkIntfID, err := getNniIntfID(classifier, action)
883 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800884 return NewErrNotFound("nni-interface-id", log.Fields{
885 "classifier": classifier,
886 "action": action},
887 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000888 }
889
890 // Clear the action map
891 for k := range action {
892 delete(action, k)
893 }
894
895 action[TrapToHost] = true
896 classifier[PacketTagType] = SingleTag
897 delete(classifier, VlanVid)
898
899 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530900 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800901 log.Debug("Flow-exists-not-re-adding")
902 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000903 }
904
npujarec5762e2020-01-01 14:08:48 +0530905 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 +0000906
907 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800908 return NewErrNotFound("flow-id", log.Fields{
909 "interface-id": intfID,
910 "oni-id": onuID,
911 "cookie": flowStoreCookie,
912 "flow-type": flowType},
913 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000914 }
915
916 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
917
David K. Bainbridge794735f2020-02-11 21:01:37 -0800918 classifierProto, err := makeOpenOltClassifierField(classifier)
919 if err != nil {
920 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000921 }
922 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800923 actionProto, err := makeOpenOltActionField(action)
924 if err != nil {
925 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000926 }
927
David K. Bainbridge794735f2020-02-11 21:01:37 -0800928 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000929 OnuId: int32(onuID),
930 UniId: int32(uniID),
931 FlowId: flowID,
932 FlowType: Upstream,
933 AllocId: int32(allocID),
934 NetworkIntfId: int32(networkIntfID),
935 GemportId: int32(gemPortID),
936 Classifier: classifierProto,
937 Action: actionProto,
938 Priority: int32(logicalFlow.Priority),
939 Cookie: logicalFlow.Cookie,
940 PortNo: portNo}
941
David K. Bainbridge794735f2020-02-11 21:01:37 -0800942 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
943 return NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
944 }
945 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000946
David K. Bainbridge794735f2020-02-11 21:01:37 -0800947 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
948 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
949 flow.OnuId,
950 flow.UniId,
951 flow.FlowId, flowsToKVStore); err != nil {
952 return NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000953 }
954
David K. Bainbridge794735f2020-02-11 21:01:37 -0800955 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000956}
957
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700958// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Girish Gowdrafae935c2020-02-17 19:21:44 +0530959func (f *OpenOltFlowMgr) addEAPOLFlow(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, vlanID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700960 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 +0530961
962 uplinkClassifier := make(map[string]interface{})
963 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530964
manikkaraj kbf256be2019-03-25 00:13:48 +0530965 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700966 uplinkClassifier[EthType] = uint32(EapEthType)
967 uplinkClassifier[PacketTagType] = SingleTag
968 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530969 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700970 uplinkAction[TrapToHost] = true
971 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530972 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800973 log.Debug("Flow-exists-not-re-adding")
974 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530975 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530976 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530977 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530978 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800979 return NewErrNotFound("flow-id", log.Fields{
980 "interface-id": intfID,
981 "onu-id": onuID,
982 "coookie": flowStoreCookie},
983 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530984 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700985 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530986
David K. Bainbridge794735f2020-02-11 21:01:37 -0800987 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
988 if err != nil {
989 return NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530990 }
991 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800992 actionProto, err := makeOpenOltActionField(uplinkAction)
993 if err != nil {
994 return NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530995 }
996 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800997 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530998 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800999 return NewErrNotFound("nni-interface-id", log.Fields{
1000 "classifier": classifier,
1001 "action": action},
1002 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301003 }
1004
David K. Bainbridge794735f2020-02-11 21:01:37 -08001005 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001006 OnuId: int32(onuID),
1007 UniId: int32(uniID),
1008 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001009 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001010 AllocId: int32(allocID),
1011 NetworkIntfId: int32(networkIntfID),
1012 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301013 Classifier: classifierProto,
1014 Action: actionProto,
1015 Priority: int32(logicalFlow.Priority),
1016 Cookie: logicalFlow.Cookie,
1017 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001018 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
1019 return NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
1020 }
1021 log.Debug("EAPOL UL flow added to device successfully")
1022 flowCategory := "EAPOL"
1023 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1024 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1025 upstreamFlow.OnuId,
1026 upstreamFlow.UniId,
1027 upstreamFlow.FlowId,
1028 /* lowCategory, */
1029 flowsToKVStore); err != nil {
1030 return NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301031 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301032
manikkaraj kbf256be2019-03-25 00:13:48 +05301033 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001034 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301035}
1036
David K. Bainbridge794735f2020-02-11 21:01:37 -08001037func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001038 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001039
1040 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1041 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1042 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
Andrea Campanella7acc0b92020-02-14 09:20:49 +01001043 if vlanID != ReservedVlan {
1044 vid := vlanID & VlanvIDMask
Harsh Awasthiea45af72019-08-26 02:39:00 -04001045 classifier.OVid = vid
1046 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301047 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001048 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1049 vid := uint32(metadata)
1050 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001051 classifier.IVid = vid
1052 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301053 }
Girish Gowdrafae935c2020-02-17 19:21:44 +05301054 // Use VlanPCPMask (0xff) to signify NO PCP. Else use valid PCP (0 to 7)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001055 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Girish Gowdrafae935c2020-02-17 19:21:44 +05301056 classifier.OPbits = vlanPcp
1057 } else {
1058 classifier.OPbits = VlanPCPMask
manikkaraj kbf256be2019-03-25 00:13:48 +05301059 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001060 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1061 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1062 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1063 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001064 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001065 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1066 classifier.PktTagType = pktTagType
1067
1068 switch pktTagType {
1069 case SingleTag:
1070 case DoubleTag:
1071 case Untagged:
1072 default:
David K. Bainbridge794735f2020-02-11 21:01:37 -08001073 return nil, NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301074 }
1075 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001076 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301077}
1078
David K. Bainbridge794735f2020-02-11 21:01:37 -08001079func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001080 var actionCmd openoltpb2.ActionCmd
1081 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301082 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001083 if _, ok := actionInfo[PopVlan]; ok {
1084 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301085 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001086 } else if _, ok := actionInfo[PushVlan]; ok {
1087 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301088 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001089 } else if _, ok := actionInfo[TrapToHost]; ok {
1090 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301091 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001092 return nil, NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301093 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001094 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301095}
1096
Manikkaraj kb1d51442019-07-23 10:41:02 -04001097func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1098 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301099}
1100
Gamze Abakafee36392019-10-03 11:17:24 +00001101// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301102func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1103 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001104 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001105 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301106 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +00001107 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 +05301108 // return err
1109 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001110 }
1111 }
1112 return nil
1113}
1114
1115// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301116func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001117 if uniPortName == "" {
1118 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1119 }
npujarec5762e2020-01-01 14:08:48 +05301120 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001121 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1122 return err
1123 }
1124 return nil
1125}
1126
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001127func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301128 if len(classifier) == 0 { // should never happen
1129 log.Error("Invalid classfier object")
1130 return 0
1131 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301132 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301133 var jsonData []byte
1134 var flowString string
1135 var err error
1136 // TODO: Do we need to marshall ??
1137 if jsonData, err = json.Marshal(classifier); err != nil {
1138 log.Error("Failed to encode classifier")
1139 return 0
1140 }
1141 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001142 if gemPortID != 0 {
1143 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301144 }
1145 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001146 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301147 hash := big.NewInt(0)
1148 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301149 generatedHash := hash.Uint64()
1150 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1151 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301152}
1153
npujarec5762e2020-01-01 14:08:48 +05301154func (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 +05301155 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001156 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001157 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1158 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1159 */
1160 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001161 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001162 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001163 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001164 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001165 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301166 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001167 if existingFlows != nil {
1168 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001169 //for _, f := range *existingFlows {
1170 // flows = append(flows, f)
1171 //}
1172 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001173 }
1174 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 +05301175 return &flows
1176}
1177
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001178//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1179// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1180// var intfId uint32
1181// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1182// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1183// */
1184// if flow.AccessIntfId != -1 {
1185// intfId = uint32(flow.AccessIntfId)
1186// } else {
1187// intfId = uint32(flow.NetworkIntfId)
1188// }
1189// // Get existing flows matching flowid for given subscriber from KV store
1190// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1191// if existingFlows != nil {
1192// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1193// for _, f := range *existingFlows {
1194// flows = append(flows, f)
1195// }
1196// }
1197// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1198// return &flows
1199//}
1200
npujarec5762e2020-01-01 14:08:48 +05301201func (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 -04001202 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301203 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001204 log.Debug("Error while Storing flow into KV store")
1205 return err
1206 }
1207 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301208 return nil
1209}
1210
David K. Bainbridge794735f2020-02-11 21:01:37 -08001211func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001212
1213 var intfID uint32
1214 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1215 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1216 */
1217 if deviceFlow.AccessIntfId != -1 {
1218 intfID = uint32(deviceFlow.AccessIntfId)
1219 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001220 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001221 intfID = uint32(deviceFlow.NetworkIntfId)
1222 }
1223
manikkaraj kbf256be2019-03-25 00:13:48 +05301224 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1225 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001226
1227 st, _ := status.FromError(err)
1228 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001229 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001230 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301231 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001232
1233 if err != nil {
1234 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301235 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001236 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001237 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301238 if deviceFlow.GemportId != -1 {
1239 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301240 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301241 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301242 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001243 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001244}
1245
David K. Bainbridge794735f2020-02-11 21:01:37 -08001246func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001247 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1248 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1249 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001250 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1251 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1252 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001253 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001254 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001255 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001256 return err
serkant.uluderya245caba2019-09-24 23:15:29 -07001257
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001258 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001259 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001260 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301261}
1262
1263/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1264 //update core flows_proxy : flows_proxy.update('/', flows)
1265}
1266
1267func generateStoredId(flowId uint32, direction string)uint32{
1268
David K. Bainbridge82efc492019-09-04 09:57:11 -07001269 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301270 log.Debug("Upstream flow shifting flowid")
1271 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001272 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301273 log.Debug("Downstream flow not shifting flowid")
1274 return flowId
1275 }else{
1276 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1277 return flowId
1278 }
1279}
1280
1281*/
1282
David K. Bainbridge794735f2020-02-11 21:01:37 -08001283func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001284
1285 classifierInfo := make(map[string]interface{})
1286 actionInfo := make(map[string]interface{})
1287
1288 classifierInfo[EthType] = uint32(LldpEthType)
1289 classifierInfo[PacketTagType] = Untagged
1290 actionInfo[TrapToHost] = true
1291
1292 // LLDP flow is installed to trap LLDP packets on the NNI port.
1293 // We manage flow_id resource pool on per PON port basis.
1294 // Since this situation is tricky, as a hack, we pass the NNI port
1295 // index (network_intf_id) as PON port Index for the flow_id resource
1296 // pool. Also, there is no ONU Id available for trapping LLDP packets
1297 // on NNI port, use onu_id as -1 (invalid)
1298 // ****************** CAVEAT *******************
1299 // This logic works if the NNI Port Id falls within the same valid
1300 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1301 // we need to have a re-look at this.
1302 // *********************************************
1303
1304 var onuID = -1
1305 var uniID = -1
1306 var gemPortID = -1
1307
David K. Bainbridge794735f2020-02-11 21:01:37 -08001308 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1309 if err != nil {
1310 return NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
1311 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001312 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301313 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001314 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001315 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001316 }
npujarec5762e2020-01-01 14:08:48 +05301317 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001318
1319 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001320 return NewErrNotFound("flow-id", log.Fields{
1321 "interface-id": networkInterfaceID,
1322 "onu-id": onuID,
1323 "uni-id": uniID,
1324 "gem-port-id": gemPortID,
1325 "cookie": flowStoreCookie},
1326 err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001327 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001328 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1329 if err != nil {
1330 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001331 }
1332 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001333 actionProto, err := makeOpenOltActionField(actionInfo)
1334 if err != nil {
1335 return NewErrInvalidValue(log.Fields{"action": actionInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001336 }
1337 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1338
1339 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1340 OnuId: int32(onuID), // OnuId not required
1341 UniId: int32(uniID), // UniId not used
1342 FlowId: flowID,
1343 FlowType: Downstream,
1344 NetworkIntfId: int32(networkInterfaceID),
1345 GemportId: int32(gemPortID),
1346 Classifier: classifierProto,
1347 Action: actionProto,
1348 Priority: int32(flow.Priority),
1349 Cookie: flow.Cookie,
1350 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001351 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
1352 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001353 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001354 log.Debug("LLDP trap on NNI flow added to device successfully")
1355 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1356 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1357 int32(onuID),
1358 int32(uniID),
1359 flowID, flowsToKVStore); err != nil {
1360 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
1361 }
1362 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301363}
1364
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301365func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001366 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1367}
1368
1369//getOnuChildDevice to fetch onu
1370func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1371 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1372 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001373 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1374 if err != nil {
1375 return nil, NewErrNotFound("onu", log.Fields{
1376 "interface-id": parentPortNo,
1377 "onu-id": onuID},
1378 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301379 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301380 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1381 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301382}
1383
1384func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001385 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301386 return nil
1387}
1388
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001389func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1390 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301391}
1392
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001393func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001394 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001395 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001396 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001397 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001398}
1399
Girish Gowdra6b130582019-11-20 16:45:20 +05301400func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1401 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1402 if err != nil {
1403 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1404 return err
1405 }
1406
1407 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1408 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1409 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1410 delGemPortMsg,
1411 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1412 f.deviceHandler.deviceType,
1413 onuDevice.Type,
1414 onuDevice.Id,
1415 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1416 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1417 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1418 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1419 return sendErr
1420 }
1421 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1422 return nil
1423}
1424
1425func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1426 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1427 if err != nil {
1428 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1429 return err
1430 }
1431
1432 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1433 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1434 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1435 delTcontMsg,
1436 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1437 f.deviceHandler.deviceType,
1438 onuDevice.Type,
1439 onuDevice.Id,
1440 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1441 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1442 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1443 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1444 return sendErr
1445 }
1446 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1447 return nil
1448}
1449
Girish Gowdra3d633032019-12-10 16:37:05 +05301450func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1451 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1452 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1453 if val.(int) > 0 {
1454 pnFlDels := val.(int) - 1
1455 if pnFlDels > 0 {
1456 log.Debugw("flow delete succeeded, more pending",
1457 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1458 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1459 } else {
1460 log.Debugw("all pending flow deletes handled, removing entry from map",
1461 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1462 f.pendingFlowDelete.Delete(pnFlDelKey)
1463 }
1464 }
1465 } else {
1466 log.Debugw("no pending delete flows found",
1467 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1468
1469 }
1470
1471}
1472
Girish Gowdrac3037402020-01-22 20:29:53 +05301473// Once the gemport is released for a given onu, it also has to be cleared from local cache
1474// which was used for deriving the gemport->logicalPortNo during packet-in.
1475// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1476// is conveyed to ONOS during packet-in OF message.
1477func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1478 f.lockCache.Lock()
1479 defer f.lockCache.Unlock()
1480 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001481 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301482 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001483 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301484 // If the gemport is found, delete it from local cache.
1485 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001486 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1487 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301488 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001489 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301490 break
1491 }
1492 }
1493 break
1494 }
1495 }
1496}
1497
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301498//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301499func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301500 gemPortID int32, flowID uint32, flowDirection string,
1501 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001502
Chaitrashree G S90a17952019-11-14 21:51:21 -05001503 tpID, err := getTpIDFromFlow(flow)
1504 if err != nil {
1505 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1506 return err
1507 }
Gamze Abakafee36392019-10-03 11:17:24 +00001508
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001509 if len(updatedFlows) >= 0 {
1510 // There are still flows referencing the same flow_id.
1511 // So the flow should not be freed yet.
1512 // For ex: Case of HSIA where same flow is shared
1513 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301514 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001515 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301516 // Do this for subscriber flows only (not trap from NNI flows)
1517 if onuID != -1 && uniID != -1 {
1518 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1519 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1520 log.Debugw("creating entry for pending flow delete",
1521 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1522 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1523 } else {
1524 pnFlDels := val.(int) + 1
1525 log.Debugw("updating flow delete entry",
1526 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1527 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1528 }
1529
1530 defer f.deletePendingFlows(Intf, onuID, uniID)
1531 }
1532
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301533 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301534 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001535
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301536 uni := getUniPortPath(Intf, onuID, uniID)
1537 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001538 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301539 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001540 if err != nil { // This should not happen, something wrong in KV backend transaction
1541 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301542 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001543 }
1544 if techprofileInst == nil {
1545 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301546 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001547 }
1548
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301549 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001550 if f.isGemPortUsedByAnotherFlow(gemPK) {
1551 flowIDs := f.flowsUsedByGemPort[gemPK]
1552 for i, flowIDinMap := range flowIDs {
1553 if flowIDinMap == flowID {
1554 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301555 // everytime flowsUsedByGemPort cache is updated the same should be updated
1556 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001557 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301558 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001559 break
1560 }
1561 }
1562 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301563 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001564 }
Gamze Abakafee36392019-10-03 11:17:24 +00001565 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301566 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001567 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1568 // 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 +05301569 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301570 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001571 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301572 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1573 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001574 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301575 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1576 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001577 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301578 // Delete the gem port on the ONU.
1579 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1580 log.Errorw("error processing delete gem-port towards onu",
1581 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1582 }
Gamze Abakafee36392019-10-03 11:17:24 +00001583
npujarec5762e2020-01-01 14:08:48 +05301584 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001585 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301586 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1587 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1588 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1589 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1590 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301591 // Delete the TCONT on the ONU.
1592 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1593 log.Errorw("error processing delete tcont towards onu",
1594 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1595 }
Gamze Abakafee36392019-10-03 11:17:24 +00001596 }
1597 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001598 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301599 return nil
1600}
1601
David K. Bainbridge794735f2020-02-11 21:01:37 -08001602// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301603func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301604
1605 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001606
1607 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301608 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001609 return
1610 }
1611
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301612 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301613 classifierInfo := make(map[string]interface{})
1614
1615 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1616 if err != nil {
1617 log.Error(err)
1618 return
1619 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301620
David K. Bainbridge794735f2020-02-11 21:01:37 -08001621 onuID := int32(onu)
1622 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301623
1624 for _, field := range flows.GetOfbFields(flow) {
1625 if field.Type == flows.IP_PROTO {
1626 classifierInfo[IPProto] = field.GetIpProto()
1627 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1628 }
1629 }
1630 log.Debugw("Extracted access info from flow to be deleted",
1631 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1632
1633 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1634 onuID = -1
1635 uniID = -1
1636 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001637 Intf, err = IntfIDFromNniPortNum(inPort)
1638 if err != nil {
1639 log.Errorw("invalid-in-port-number",
1640 log.Fields{
1641 "port-number": inPort,
1642 "error": err})
1643 return
1644 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301645 }
npujarec5762e2020-01-01 14:08:48 +05301646 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001647 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301648 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301649 if flowInfo == nil {
1650 log.Debugw("No FlowInfo found found in KV store",
1651 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1652 return
1653 }
1654 updatedFlows = nil
1655 for _, flow := range *flowInfo {
1656 updatedFlows = append(updatedFlows, flow)
1657 }
1658
1659 for i, storedFlow := range updatedFlows {
1660 if flow.Id == storedFlow.LogicalFlowID {
1661 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1662 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001663 // DKB
1664 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1665 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1666 return
1667 }
1668 log.Debug("Flow removed from device successfully")
1669 //Remove the Flow from FlowInfo
1670 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1671 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1672 flowID, flowDirection, portNum, updatedFlows); err != nil {
1673 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301674 return
1675 }
1676 }
1677 }
1678 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001679}
1680
Esin Karamanccb714b2019-11-29 15:02:06 +00001681//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1682// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301683func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001684 classifierInfo := make(map[string]interface{})
1685 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301686 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001687
1688 if err != nil {
1689 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1690 return
1691 }
1692
David K. Bainbridge794735f2020-02-11 21:01:37 -08001693 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1694 if err != nil {
1695 // DKB
1696 log.Errorw("invalid-in-port-number",
1697 log.Fields{
1698 "port-number": inPort,
1699 "error": err})
1700 return
1701 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001702 var onuID = int32(NoneOnuID)
1703 var uniID = int32(NoneUniID)
1704 var flowID uint32
1705 var updatedFlows []rsrcMgr.FlowInfo
1706
npujarec5762e2020-01-01 14:08:48 +05301707 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001708
1709 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301710 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001711 if flowInfo == nil {
1712 log.Debugw("No multicast FlowInfo found in the KV store",
1713 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1714 continue
1715 }
1716 updatedFlows = nil
1717 for _, flow := range *flowInfo {
1718 updatedFlows = append(updatedFlows, flow)
1719 }
1720 for i, storedFlow := range updatedFlows {
1721 if flow.Id == storedFlow.LogicalFlowID {
1722 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1723 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1724 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001725 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1726 // DKB
1727 log.Errorw("failed-to-remove-multicast-flow",
1728 log.Fields{
1729 "flow-id": flow.Id,
1730 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001731 return
1732 }
1733 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1734 //Remove the Flow from FlowInfo
1735 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301736 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001737 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1738 return
1739 }
1740 //release flow id
1741 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301742 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001743 }
1744 }
1745 }
1746}
1747
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001748//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301749func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001750 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301751 var direction string
1752 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001753
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301754 for _, action := range flows.GetActions(flow) {
1755 if action.Type == flows.OUTPUT {
1756 if out := action.GetOutput(); out != nil {
1757 actionInfo[Output] = out.GetPort()
1758 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1759 } else {
1760 log.Error("Invalid output port in action")
1761 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001762 }
1763 }
1764 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001765
1766 if flows.HasGroup(flow) {
1767 direction = Multicast
1768 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301769 direction = Upstream
1770 } else {
1771 direction = Downstream
1772 }
npujarec5762e2020-01-01 14:08:48 +05301773 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301774
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001775 return
1776}
1777
Girish Gowdra3d633032019-12-10 16:37:05 +05301778func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1779 uniID uint32, ch chan bool) {
1780 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1781 for {
1782 select {
1783 case <-time.After(20 * time.Millisecond):
1784 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1785 log.Debug("pending flow deletes completed")
1786 ch <- true
1787 return
1788 }
1789 case <-ctx.Done():
1790 log.Error("flow delete wait handler routine canceled")
1791 return
1792 }
1793 }
1794}
1795
Esin Karamanae41e2b2019-12-17 18:13:13 +00001796//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1797func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1798 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1799 if ethType, ok := classifierInfo[EthType]; ok {
1800 if ethType.(uint32) == IPv4EthType {
1801 if ipProto, ok := classifierInfo[IPProto]; ok {
1802 if ipProto.(uint32) == IgmpProto {
1803 return true
1804 }
1805 }
1806 }
1807 }
1808 }
1809 return false
1810}
1811
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001812// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301813// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301814func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001815 classifierInfo := make(map[string]interface{})
1816 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001817 var UsMeterID uint32
1818 var DsMeterID uint32
1819
1820 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001821 formulateClassifierInfoFromFlow(classifierInfo, flow)
1822
1823 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1824 if err != nil {
1825 // Error logging is already done in the called function
1826 // So just return in case of error
1827 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301828 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001829
Esin Karamanccb714b2019-11-29 15:02:06 +00001830 if flows.HasGroup(flow) {
1831 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301832 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001833 return
1834 }
1835
manikkaraj k17652a72019-05-06 09:06:36 -04001836 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001837 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1838 if err != nil {
1839 // error if any, already logged in the called function
1840 return
manikkaraj k17652a72019-05-06 09:06:36 -04001841 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001842
David K. Bainbridge82efc492019-09-04 09:57:11 -07001843 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1844 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001845
Humera Kouser94d7a842019-08-25 19:04:32 -04001846 if ethType, ok := classifierInfo[EthType]; ok {
1847 if ethType.(uint32) == LldpEthType {
1848 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301849 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001850 return
1851 }
1852 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001853 if ipProto, ok := classifierInfo[IPProto]; ok {
1854 if ipProto.(uint32) == IPProtoDhcp {
1855 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301856 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001857 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301858 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001859 return
1860 }
1861 }
1862 }
1863 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001864 if isIgmpTrapDownstreamFlow(classifierInfo) {
1865 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301866 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001867 return
1868 }
A R Karthick1f85b802019-10-11 05:06:05 +00001869
1870 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301871 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001872
Chaitrashree G S90a17952019-11-14 21:51:21 -05001873 TpID, err := getTpIDFromFlow(flow)
1874 if err != nil {
1875 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1876 return
1877 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001878 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001879 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001880 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001881 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1882 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001883 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001884 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1885
1886 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301887
1888 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1889 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1890 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 +05301891 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301892 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301893 pendingFlowDelComplete := make(chan bool)
1894 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1895 select {
1896 case <-pendingFlowDelComplete:
1897 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301898 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301899
1900 case <-time.After(10 * time.Second):
1901 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1902 }
1903 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001904}
1905
Esin Karamanccb714b2019-11-29 15:02:06 +00001906// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001907func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001908 classifierInfo[PacketTagType] = DoubleTag
1909 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1910
npujarec5762e2020-01-01 14:08:48 +05301911 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001912 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001913 return NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001914 }
1915 //replace ipDst with ethDst
1916 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1917 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1918 // replace ipv4_dst classifier with eth_dst
1919 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1920 delete(classifierInfo, Ipv4Dst)
1921 delete(classifierInfo, EthType)
1922 classifierInfo[EthDst] = multicastMac
1923 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1924 }
1925
David K. Bainbridge794735f2020-02-11 21:01:37 -08001926 onuID := NoneOnuID
1927 uniID := NoneUniID
1928 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001929
David K. Bainbridge794735f2020-02-11 21:01:37 -08001930 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1931 if err != nil {
1932 return NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
1933 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001934
David K. Bainbridge794735f2020-02-11 21:01:37 -08001935 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301936 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001937 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1938 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001939 }
npujarec5762e2020-01-01 14:08:48 +05301940 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001941 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001942 return NewErrNotFound("multicast-flow-id", log.Fields{
1943 "interface-id": networkInterfaceID,
1944 "onu-id": onuID,
1945 "uni-id": uniID,
1946 "gem-port-id": gemPortID,
1947 "cookie": flowStoreCookie},
1948 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001949 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001950 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1951 if err != nil {
1952 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001953 }
1954 groupID := actionInfo[GroupID].(uint32)
1955 multicastFlow := openoltpb2.Flow{
1956 FlowId: flowID,
1957 FlowType: Multicast,
1958 NetworkIntfId: int32(networkInterfaceID),
1959 GroupId: groupID,
1960 Classifier: classifierProto,
1961 Priority: int32(flow.Priority),
1962 Cookie: flow.Cookie}
1963
David K. Bainbridge794735f2020-02-11 21:01:37 -08001964 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
1965 return NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1966 }
1967 log.Debug("multicast flow added to device successfully")
1968 //get cached group
1969 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1970 if err == nil {
1971 //calling groupAdd to set group members after multicast flow creation
1972 if f.ModifyGroup(ctx, group) {
1973 //cached group can be removed now
1974 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001975 }
1976 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001977
1978 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1979 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1980 int32(onuID),
1981 int32(uniID),
1982 flowID, flowsToKVStore); err != nil {
1983 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1984 }
1985 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001986}
1987
1988//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301989func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001990 if _, ok := classifierInfo[InPort]; ok {
1991 return classifierInfo[InPort].(uint32), nil
1992 }
1993 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301994 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001995 if e == nil && len(nniPorts) > 0 {
1996 return nniPorts[0], nil
1997 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001998 return 0, NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001999}
2000
2001// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05302002func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00002003 log.Infow("add-group", log.Fields{"group": group})
2004 if group == nil {
2005 log.Warn("skipping nil group")
2006 return
2007 }
2008
2009 groupToOlt := openoltpb2.Group{
2010 GroupId: group.Desc.GroupId,
2011 Command: openoltpb2.Group_SET_MEMBERS,
2012 Action: f.buildGroupAction(),
2013 }
2014
2015 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302016 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002017 if err != nil {
2018 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
2019 return
2020 }
2021 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302022 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002023 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
2024 } else {
2025 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2026 }
2027}
2028
2029//buildGroupAction creates and returns a group action
2030func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2031 var actionCmd openoltpb2.ActionCmd
2032 var action openoltpb2.Action
2033 action.Cmd = &actionCmd
2034 //pop outer vlan
2035 action.Cmd.RemoveOuterTag = true
2036 return &action
2037}
2038
2039// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05302040func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00002041 log.Infow("modify-group", log.Fields{"group": group})
2042 if group == nil || group.Desc == nil {
2043 log.Warn("cannot modify group; group is nil")
2044 return false
2045 }
2046
2047 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2048 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302049 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002050
2051 if err != nil {
2052 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2053 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2054 return false
2055 }
2056
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002057 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002058 if groupExists {
2059 // group already exists
2060 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002061 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002062 } else {
2063 current = f.buildGroup(group.Desc.GroupId, nil)
2064 }
2065
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002066 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2067 // get members to be added
2068 membersToBeAdded := f.findDiff(current, new)
2069 // get members to be removed
2070 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002071
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002072 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2073 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002074
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002075 groupToOlt := openoltpb2.Group{
2076 GroupId: group.Desc.GroupId,
2077 }
2078 var added, removed = true, true
2079 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2080 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2081 groupToOlt.Members = membersToBeAdded
2082 //execute addMembers
2083 added = f.callGroupAddRemove(&groupToOlt)
2084 }
2085 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2086 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2087 groupToOlt.Members = membersToBeRemoved
2088 //execute removeMembers
2089 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002090 }
2091
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002092 //save the modified group
2093 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302094 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002095 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2096 }
2097 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002098 } else {
2099 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2100 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002101 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002102 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002103}
2104
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002105//callGroupAddRemove performs add/remove buckets operation for the indicated group
2106func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2107 if err := f.performGroupOperation(group); err != nil {
2108 st, _ := status.FromError(err)
2109 //ignore already exists error code
2110 if st.Code() != codes.AlreadyExists {
2111 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002112 }
2113 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002114 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002115}
2116
2117//findDiff compares group members and finds members which only exists in groups2
2118func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2119 var members []*openoltpb2.GroupMember
2120 for _, bucket := range group2.Members {
2121 if !f.contains(group1.Members, bucket) {
2122 // bucket does not exist and must be added
2123 members = append(members, bucket)
2124 }
2125 }
2126 return members
2127}
2128
2129//contains returns true if the members list contains the given member; false otherwise
2130func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2131 for _, groupMember := range members {
2132 if groupMember.InterfaceId == member.InterfaceId {
2133 return true
2134 }
2135 }
2136 return false
2137}
2138
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002139//performGroupOperation call performGroupOperation operation of openolt proto
2140func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002141 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2142 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2143 if err != nil {
2144 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2145 }
2146 return err
2147}
2148
2149//buildGroup build openoltpb2.Group from given group id and bucket list
2150func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2151 group := openoltpb2.Group{
2152 GroupId: groupID}
2153 // create members of the group
2154 if buckets != nil {
2155 for _, ofBucket := range buckets {
2156 member := f.buildMember(ofBucket)
2157 if member != nil && !f.contains(group.Members, member) {
2158 group.Members = append(group.Members, member)
2159 }
2160 }
2161 }
2162 return &group
2163}
2164
2165//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2166func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2167 var outPort uint32
2168 outPortFound := false
2169 for _, ofAction := range ofBucket.Actions {
2170 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2171 outPort = ofAction.GetOutput().Port
2172 outPortFound = true
2173 }
2174 }
2175
2176 if !outPortFound {
2177 log.Debugw("bucket skipped since no out port found in it",
2178 log.Fields{"ofBucket": ofBucket})
2179 return nil
2180 }
2181 interfaceID := IntfIDFromUniPortNum(outPort)
2182 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2183 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2184 member := openoltpb2.GroupMember{
2185 InterfaceId: interfaceID,
2186 InterfaceType: openoltpb2.GroupMember_PON,
2187 GemPortId: groupInfo.gemPortID,
2188 Priority: groupInfo.servicePriority,
2189 }
2190 //add member to the group
2191 return &member
2192 }
2193 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2194 log.Fields{"ofBucket": ofBucket})
2195 return nil
2196}
2197
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002198//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002199func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002200
2201 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302202 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002203 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302204 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302205 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302206 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002207
Manikkaraj kb1d51442019-07-23 10:41:02 -04002208 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002209 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002210 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2211 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2212 tpDownloadMsg,
2213 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2214 f.deviceHandler.deviceType,
2215 onuDevice.Type,
2216 onuDevice.Id,
2217 onuDevice.ProxyAddress.DeviceId, "")
2218 if sendErr != nil {
2219 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2220 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2221 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2222 return sendErr
2223 }
2224 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302225 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302226}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002227
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302228//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302229func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302230
2231 f.lockCache.Lock()
2232 defer f.lockCache.Unlock()
2233 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2234 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002235 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2236 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302237 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2238 return
2239 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002240 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2241}
2242
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302243//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302244func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302245 f.lockCache.Lock()
2246 defer f.lockCache.Unlock()
2247 onugem := f.onuGemInfo[intfID]
2248 // update the gem to the local cache as well as to kv strore
2249 for idx, onu := range onugem {
2250 if onu.OnuID == onuID {
2251 // check if gem already exists , else update the cache and kvstore
2252 for _, gem := range onu.GemPorts {
2253 if gem == gemPort {
2254 log.Debugw("Gem already in cache, no need to update cache and kv store",
2255 log.Fields{"gem": gemPort})
2256 return
2257 }
2258 }
2259 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2260 f.onuGemInfo[intfID] = onugem
2261 }
2262 }
npujarec5762e2020-01-01 14:08:48 +05302263 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302264 if err != nil {
2265 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002266 return
2267 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002268}
2269
2270// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002271
2272//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2273func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302274
2275 f.lockCache.Lock()
2276 defer f.lockCache.Unlock()
2277
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002278 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 +05302279 // get onuid from the onugem info cache
2280 onugem := f.onuGemInfo[intfID]
2281 for _, onu := range onugem {
2282 for _, gem := range onu.GemPorts {
2283 if gem == gemPortID {
2284 return onu.OnuID, nil
2285 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002286 }
2287 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002288 return uint32(0), NewErrNotFound("onu-id", log.Fields{
2289 "serial-number": serialNumber,
2290 "interface-id": intfID,
2291 "gem-port-id": gemPortID},
2292 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002293}
2294
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002295//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302296func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002297 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002298 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002299 var err error
2300
2301 if packetIn.IntfType == "pon" {
2302 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002303 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002304 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2305 return logicalPortNum, err
2306 }
2307 if packetIn.PortNo != 0 {
2308 logicalPortNum = packetIn.PortNo
2309 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002310 uniID := uint32(0) // FIXME - multi-uni support
2311 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002312 }
2313 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302314 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002315 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002316 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002317 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002318 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2319 "logicalPortNum": logicalPortNum,
2320 "IntfType": packetIn.IntfType,
2321 "packet": hex.EncodeToString(packetIn.Pkt),
2322 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002323 return logicalPortNum, nil
2324}
2325
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002326//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302327func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002328 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002329 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302330
2331 f.lockCache.Lock()
2332 defer f.lockCache.Unlock()
2333 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2334
2335 gemPortID, ok := f.packetInGemPort[pktInkey]
2336 if ok {
2337 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2338 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002339 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302340 //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 +05302341 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302342 if err == nil {
2343 if gemPortID != 0 {
2344 f.packetInGemPort[pktInkey] = gemPortID
2345 log.Debugw("Found gem port from kv store and updating cache with gemport",
2346 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2347 return gemPortID, nil
2348 }
2349 }
2350 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2351 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002352}
2353
npujarec5762e2020-01-01 14:08:48 +05302354func installFlowOnAllGemports(ctx context.Context,
2355 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002356 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002357 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302358 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302359 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302360 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302361 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002362 args map[string]uint32,
2363 classifier map[string]interface{}, action map[string]interface{},
2364 logicalFlow *ofp.OfpFlowStats,
2365 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302366 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002367 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002368 vlanID ...uint32) {
2369 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302370
2371 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2372 var gemPortID uint32
2373 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2374 // We need to trim prefix "0b", before further processing
2375 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2376 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2377 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2378 // If a particular character in the string is set to '1', identify the index of this character from
2379 // the LSB position which marks the PCP bit consumed by the given gem port.
2380 // This PCP bit now becomes a classifier in the flow.
2381 if pbitSet == BinaryBit1 {
2382 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2383 gemPortID = gemPortAttribute.GemportID
2384 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2385 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2386 } else if FlowType == EapolFlow {
2387 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2388 } else {
2389 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2390 return
2391 }
2392 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002393 }
2394 }
2395}
2396
David K. Bainbridge794735f2020-02-11 21:01:37 -08002397func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002398 log.Debug("Adding trap-dhcp-of-nni-flow")
2399 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002400 classifier[PacketTagType] = DoubleTag
2401 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002402 /* We manage flowId resource pool on per PON port basis.
2403 Since this situation is tricky, as a hack, we pass the NNI port
2404 index (network_intf_id) as PON port Index for the flowId resource
2405 pool. Also, there is no ONU Id available for trapping DHCP packets
2406 on NNI port, use onu_id as -1 (invalid)
2407 ****************** CAVEAT *******************
2408 This logic works if the NNI Port Id falls within the same valid
2409 range of PON Port Ids. If this doesn't work for some OLT Vendor
2410 we need to have a re-look at this.
2411 *********************************************
2412 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002413 onuID := -1
2414 uniID := -1
2415 gemPortID := -1
2416 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002417 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302418 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002419 return NewErrNotFound("nni-intreface-id", log.Fields{
2420 "classifier": classifier,
2421 "action": action},
2422 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302423 }
2424
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002425 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302426 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002427 log.Debug("Flow-exists-not-re-adding")
2428 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002429 }
npujarec5762e2020-01-01 14:08:48 +05302430 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002431 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002432 return NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
2433 "interface-id": networkInterfaceID,
2434 "onu-id": onuID,
2435 "uni-id": uniID,
2436 "gem-port-id": gemPortID,
2437 "cookie": flowStoreCookie},
2438 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002439 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002440 classifierProto, err := makeOpenOltClassifierField(classifier)
2441 if err != nil {
2442 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002443 }
2444 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002445 actionProto, err := makeOpenOltActionField(action)
2446 if err != nil {
2447 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002448 }
2449 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002450 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2451 OnuId: int32(onuID), // OnuId not required
2452 UniId: int32(uniID), // UniId not used
2453 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002454 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002455 AllocId: int32(allocID), // AllocId not used
2456 NetworkIntfId: int32(networkInterfaceID),
2457 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002458 Classifier: classifierProto,
2459 Action: actionProto,
2460 Priority: int32(logicalFlow.Priority),
2461 Cookie: logicalFlow.Cookie,
2462 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002463 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2464 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002465 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002466 log.Debug("DHCP trap on NNI flow added to device successfully")
2467 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2468 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2469 int32(onuID),
2470 int32(uniID),
2471 flowID, flowsToKVStore); err != nil {
2472 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2473 }
2474 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002475}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002476
Esin Karamanae41e2b2019-12-17 18:13:13 +00002477//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2478func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2479 var packetType string
2480 ovid, ivid := false, false
2481 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2482 vid := vlanID & VlanvIDMask
2483 if vid != ReservedVlan {
2484 ovid = true
2485 }
2486 }
2487 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2488 vid := uint32(metadata)
2489 if vid != ReservedVlan {
2490 ivid = true
2491 }
2492 }
2493 if ovid && ivid {
2494 packetType = DoubleTag
2495 } else if !ovid && !ivid {
2496 packetType = Untagged
2497 } else {
2498 packetType = SingleTag
2499 }
2500 return packetType
2501}
2502
2503//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002504func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002505 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2506 action := make(map[string]interface{})
2507 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2508 action[TrapToHost] = true
2509 /* We manage flowId resource pool on per PON port basis.
2510 Since this situation is tricky, as a hack, we pass the NNI port
2511 index (network_intf_id) as PON port Index for the flowId resource
2512 pool. Also, there is no ONU Id available for trapping packets
2513 on NNI port, use onu_id as -1 (invalid)
2514 ****************** CAVEAT *******************
2515 This logic works if the NNI Port Id falls within the same valid
2516 range of PON Port Ids. If this doesn't work for some OLT Vendor
2517 we need to have a re-look at this.
2518 *********************************************
2519 */
2520 onuID := -1
2521 uniID := -1
2522 gemPortID := -1
2523 allocID := -1
2524 networkInterfaceID, err := getNniIntfID(classifier, action)
2525 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002526 return NewErrNotFound("nni-interface-id", log.Fields{
2527 "classifier": classifier,
2528 "action": action},
2529 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002530 }
2531 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302532 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002533 log.Debug("igmp-flow-exists-not-re-adding")
2534 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002535 }
npujarec5762e2020-01-01 14:08:48 +05302536 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002537 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002538 return NewErrNotFound("igmp-flow-id", log.Fields{
2539 "interface-id": networkInterfaceID,
2540 "onu-id": onuID,
2541 "uni-id": uniID,
2542 "gem-port-id": gemPortID,
2543 "cookie": flowStoreCookie},
2544 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002545 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002546 classifierProto, err := makeOpenOltClassifierField(classifier)
2547 if err != nil {
2548 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002549 }
2550 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002551 actionProto, err := makeOpenOltActionField(action)
2552 if err != nil {
2553 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002554 }
2555 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2556 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2557 OnuId: int32(onuID), // OnuId not required
2558 UniId: int32(uniID), // UniId not used
2559 FlowId: flowID,
2560 FlowType: Downstream,
2561 AllocId: int32(allocID), // AllocId not used
2562 NetworkIntfId: int32(networkInterfaceID),
2563 GemportId: int32(gemPortID), // GemportId not used
2564 Classifier: classifierProto,
2565 Action: actionProto,
2566 Priority: int32(logicalFlow.Priority),
2567 Cookie: logicalFlow.Cookie,
2568 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002569 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2570 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002571 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002572 log.Debug("IGMP Trap on NNI flow added to device successfully")
2573 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2574 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2575 int32(onuID),
2576 int32(uniID),
2577 flowID, flowsToKVStore); err != nil {
2578 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2579 }
2580 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002581}
2582
salmansiddiqui7ac62132019-08-22 03:58:50 +00002583func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2584 if MeterID == 0 { // This should never happen
David K. Bainbridge794735f2020-02-11 21:01:37 -08002585 return "", NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002586 }
2587 if Dir == tp_pb.Direction_UPSTREAM {
2588 return "upstream", nil
2589 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2590 return "downstream", nil
2591 }
2592 return "", nil
2593}
2594
npujarec5762e2020-01-01 14:08:48 +05302595func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002596 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2597 TpID uint32, uni string) {
2598 var gemPort uint32
2599 intfID := args[IntfID]
2600 onuID := args[OnuID]
2601 uniID := args[UniID]
2602 portNo := args[PortNo]
2603 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002604 if ipProto, ok := classifierInfo[IPProto]; ok {
2605 if ipProto.(uint32) == IPProtoDhcp {
2606 log.Info("Adding DHCP flow")
2607 if pcp, ok := classifierInfo[VlanPcp]; ok {
2608 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2609 tp_pb.Direction_UPSTREAM,
2610 pcp.(uint32))
2611 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302612 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002613 } else {
2614 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302615 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002616 }
2617
2618 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002619 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2620 if pcp, ok := classifierInfo[VlanPcp]; ok {
2621 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2622 tp_pb.Direction_UPSTREAM,
2623 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302624 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002625 } else {
2626 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302627 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002628 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002629 } else {
2630 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2631 return
2632 }
2633 } else if ethType, ok := classifierInfo[EthType]; ok {
2634 if ethType.(uint32) == EapEthType {
2635 log.Info("Adding EAPOL flow")
2636 var vlanID uint32
2637 if val, ok := classifierInfo[VlanVid]; ok {
2638 vlanID = (val.(uint32)) & VlanvIDMask
2639 } else {
2640 vlanID = DefaultMgmtVlan
2641 }
2642 if pcp, ok := classifierInfo[VlanPcp]; ok {
2643 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2644 tp_pb.Direction_UPSTREAM,
2645 pcp.(uint32))
2646
Girish Gowdrafae935c2020-02-17 19:21:44 +05302647 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002648 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302649 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002650 }
2651 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002652 } else if _, ok := actionInfo[PushVlan]; ok {
2653 log.Info("Adding upstream data rule")
2654 if pcp, ok := classifierInfo[VlanPcp]; ok {
2655 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2656 tp_pb.Direction_UPSTREAM,
2657 pcp.(uint32))
2658 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302659 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002660 } else {
2661 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302662 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002663 }
2664 } else if _, ok := actionInfo[PopVlan]; ok {
2665 log.Info("Adding Downstream data rule")
2666 if pcp, ok := classifierInfo[VlanPcp]; ok {
2667 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002668 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002669 pcp.(uint32))
2670 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302671 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002672 } else {
2673 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302674 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002675 }
2676 } else {
2677 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2678 return
2679 }
2680 // Send Techprofile download event to child device in go routine as it takes time
2681 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2682}
2683
Gamze Abakafee36392019-10-03 11:17:24 +00002684func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2685 flowIDList := f.flowsUsedByGemPort[gemPK]
2686 if len(flowIDList) > 1 {
2687 return true
2688 }
2689 return false
2690}
2691
npujarec5762e2020-01-01 14:08:48 +05302692func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2693 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002694 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2695 for _, currentGemPort := range currentGemPorts {
2696 for _, tpGemPort := range tpGemPorts {
2697 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2698 return true, currentGemPort
2699 }
2700 }
2701 }
Girish Gowdra54934262019-11-13 14:19:55 +05302702 if tpInst.InstanceCtrl.Onu == "single-instance" {
2703 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302704 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2705 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302706
2707 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2708 // still be used on other uni ports.
2709 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2710 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302711 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302712 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302713 for i := 0; i < len(tpInstances); i++ {
2714 tpI := tpInstances[i]
2715 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302716 for _, tpGemPort := range tpGemPorts {
2717 if tpGemPort.GemportID != gemPortID {
2718 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2719 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302720 }
2721 }
2722 }
2723 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302724 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002725 return false, 0
2726}
2727
salmansiddiqui7ac62132019-08-22 03:58:50 +00002728func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002729 for _, field := range flows.GetOfbFields(flow) {
2730 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002731 classifierInfo[EthType] = field.GetEthType()
2732 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002733 } else if field.Type == flows.ETH_DST {
2734 classifierInfo[EthDst] = field.GetEthDst()
2735 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002736 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002737 classifierInfo[IPProto] = field.GetIpProto()
2738 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002739 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002740 classifierInfo[InPort] = field.GetPort()
2741 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002742 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302743 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002744 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002745 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002746 classifierInfo[VlanPcp] = field.GetVlanPcp()
2747 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002748 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002749 classifierInfo[UDPDst] = field.GetUdpDst()
2750 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002751 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002752 classifierInfo[UDPSrc] = field.GetUdpSrc()
2753 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002754 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002755 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2756 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002757 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002758 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2759 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002760 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002761 classifierInfo[Metadata] = field.GetTableMetadata()
2762 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002763 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002764 classifierInfo[TunnelID] = field.GetTunnelId()
2765 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2766 } else {
2767 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2768 return
2769 }
2770 }
2771}
2772
2773func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002774 for _, action := range flows.GetActions(flow) {
2775 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002776 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002777 actionInfo[Output] = out.GetPort()
2778 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002779 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002780 return NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002781 }
Scott Baker355d1742019-10-24 10:57:52 -07002782 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002783 actionInfo[PopVlan] = true
2784 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002785 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002786 if out := action.GetPush(); out != nil {
2787 if tpid := out.GetEthertype(); tpid != 0x8100 {
2788 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2789 } else {
2790 actionInfo[PushVlan] = true
2791 actionInfo[TPID] = tpid
2792 log.Debugw("action-type-push-vlan",
2793 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2794 }
2795 }
Scott Baker355d1742019-10-24 10:57:52 -07002796 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002797 if out := action.GetSetField(); out != nil {
2798 if field := out.GetField(); field != nil {
2799 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002800 return NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002801 }
2802 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002803 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002804 }
2805 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002806 } else if action.Type == flows.GROUP {
2807 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002808 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002809 return NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002810 }
2811 }
2812 return nil
2813}
2814
Esin Karamanccb714b2019-11-29 15:02:06 +00002815func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2816 if ofbField := field.GetOfbField(); ofbField != nil {
2817 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2818 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2819 actionInfo[VlanVid] = vlan & 0xfff
2820 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2821 } else {
2822 log.Error("No Invalid vlan id in set vlan-vid action")
2823 }
2824 } else {
2825 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2826 }
2827 }
2828}
2829
2830func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2831 if action.GetGroup() == nil {
2832 log.Warn("No group entry found in the group action")
2833 } else {
2834 actionInfo[GroupID] = action.GetGroup().GroupId
2835 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2836 }
2837}
2838
salmansiddiqui7ac62132019-08-22 03:58:50 +00002839func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002840 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002841 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2842 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2843 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002844 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002845 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002846 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 +00002847 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002848 return NewErrNotFound("child-in-port", log.Fields{
2849 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2850 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002851 }
2852 }
2853 } else {
2854 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2855 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002856 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002857 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002858 actionInfo[Output] = uniPort
2859 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 +00002860 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002861 return NewErrNotFound("out-port", log.Fields{
2862 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2863 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002864 }
2865 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2866 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002867 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002868 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002869 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2870 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002871 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002872 return NewErrNotFound("nni-port", log.Fields{
2873 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2874 "in-port": classifierInfo[InPort].(uint32),
2875 "out-port": actionInfo[Output].(uint32),
2876 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002877 }
2878 }
2879 }
2880 return nil
2881}
Gamze Abakafee36392019-10-03 11:17:24 +00002882
Chaitrashree G S90a17952019-11-14 21:51:21 -05002883func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002884 /* Metadata 8 bytes:
2885 Most Significant 2 Bytes = Inner VLAN
2886 Next 2 Bytes = Tech Profile ID(TPID)
2887 Least Significant 4 Bytes = Port ID
2888 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2889 subscriber related flows.
2890 */
2891 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2892 if metadata == 0 {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002893 return 0, NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002894 }
2895 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002896 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002897}
2898
2899func appendUnique(slice []uint32, item uint32) []uint32 {
2900 for _, sliceElement := range slice {
2901 if sliceElement == item {
2902 return slice
2903 }
2904 }
2905 return append(slice, item)
2906}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302907
2908// getNniIntfID gets nni intf id from the flow classifier/action
2909func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2910
2911 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2912 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002913 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2914 if err != nil {
2915 log.Debugw("invalid-action-port-number",
2916 log.Fields{
2917 "port-number": action[Output].(uint32),
2918 "error": err})
2919 return uint32(0), err
2920 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302921 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2922 return intfID, nil
2923 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002924 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2925 if err != nil {
2926 log.Debugw("invalid-classifier-port-number",
2927 log.Fields{
2928 "port-number": action[Output].(uint32),
2929 "error": err})
2930 return uint32(0), err
2931 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302932 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2933 return intfID, nil
2934 }
2935 return uint32(0), nil
2936}
2937
2938// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302939func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302940 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2941
2942 f.lockCache.Lock()
2943 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002944 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302945 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002946 if lookupGemPort == gemPort {
2947 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2948 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2949 return
2950 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302951 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002952 f.packetInGemPort[pktInkey] = gemPort
2953
npujarec5762e2020-01-01 14:08:48 +05302954 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002955 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 +05302956 return
2957}
2958
2959// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302960func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302961
2962 f.lockCache.Lock()
2963 defer f.lockCache.Unlock()
2964 onugem := f.onuGemInfo[intfID]
2965 for idx, onu := range onugem {
2966 if onu.OnuID == onuID {
2967 for _, uni := range onu.UniPorts {
2968 if uni == portNum {
2969 log.Debugw("uni already in cache, no need to update cache and kv store",
2970 log.Fields{"uni": portNum})
2971 return
2972 }
2973 }
2974 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2975 f.onuGemInfo[intfID] = onugem
2976 }
2977 }
npujarec5762e2020-01-01 14:08:48 +05302978 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302979}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302980
npujarec5762e2020-01-01 14:08:48 +05302981func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2982 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302983 if err != nil {
2984 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2985 return
2986 }
2987 for gem, FlowIDs := range flowIDsList {
2988 gemPK := gemPortKey{intf, uint32(gem)}
2989 f.flowsUsedByGemPort[gemPK] = FlowIDs
2990 }
2991 return
2992}
Esin Karamanccb714b2019-11-29 15:02:06 +00002993
2994//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2995//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302996func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2997 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002998 if err != nil {
2999 log.Error("Failed to get pon interface to multicast queue map")
3000 return
3001 }
3002 for intf, queueInfo := range storedMulticastQueueMap {
3003 q := queueInfoBrief{
3004 gemPortID: queueInfo[0],
3005 servicePriority: queueInfo[1],
3006 }
3007 f.interfaceToMcastQueueMap[intf] = &q
3008 }
3009}
3010
3011//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
3012//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
3013//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05303014func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
3015 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00003016 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08003017 return nil, false, NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00003018 }
3019 if exists {
3020 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3021 }
3022 return nil, exists, nil
3023}
3024
3025func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3026 groupDesc := ofp.OfpGroupDesc{
3027 Type: ofp.OfpGroupType_OFPGT_ALL,
3028 GroupId: groupID,
3029 }
3030 groupEntry := ofp.OfpGroupEntry{
3031 Desc: &groupDesc,
3032 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003033 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003034 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003035 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003036 bucket := ofp.OfpBucket{
3037 Actions: acts,
3038 }
3039 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003040 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003041 return &groupEntry
3042}