blob: c6bad4666929d827fa1c3ef48c7e438308785419 [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"
Thomas Lee S94109f12020-03-03 16:39:29 +053044 "github.com/opencord/voltha-openolt-adapter/internal/pkg/olterrors"
Daniele Rossi22db98e2019-07-11 11:50:00 +000045 "google.golang.org/grpc/codes"
46 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053047)
48
49const (
50 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053051
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070052 //HsiaFlow flow category
53 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053054
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070055 //EapolFlow flow category
56 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053057
Manikkaraj kb1d51442019-07-23 10:41:02 -040058 //DhcpFlow flow category
59 DhcpFlow = "DHCP_FLOW"
60
Esin Karamanccb714b2019-11-29 15:02:06 +000061 //MulticastFlow flow category
62 MulticastFlow = "MULTICAST_FLOW"
63
Esin Karamanae41e2b2019-12-17 18:13:13 +000064 //IgmpFlow flow category
65 IgmpFlow = "IGMP_FLOW"
66
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070067 //IPProtoDhcp flow category
68 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053069
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070070 //IPProtoIgmp flow category
71 IPProtoIgmp = 2
72
73 //EapEthType eapethtype value
74 EapEthType = 0x888e
75 //LldpEthType lldp ethtype value
76 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000077 //IPv4EthType IPv4 ethernet type value
78 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070079
80 //IgmpProto proto value
81 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053082
Andrea Campanella7acc0b92020-02-14 09:20:49 +010083 //ReservedVlan Transparent Vlan (Masked Vlan, VLAN_ANY in ONOS Flows)
84 ReservedVlan = 4096
Harsh Awasthiea45af72019-08-26 02:39:00 -040085
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070086 //DefaultMgmtVlan default vlan value
87 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053088
manikkaraj kbf256be2019-03-25 00:13:48 +053089 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070090
David K. Bainbridge82efc492019-09-04 09:57:11 -070091 //Upstream constant
92 Upstream = "upstream"
93 //Downstream constant
94 Downstream = "downstream"
Esin Karamanccb714b2019-11-29 15:02:06 +000095 //Multicast constant
96 Multicast = "multicast"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070097 //PacketTagType constant
98 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -070099 //Untagged constant
100 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700101 //SingleTag constant
102 SingleTag = "single_tag"
103 //DoubleTag constant
104 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530105
106 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700107
108 //EthType constant
109 EthType = "eth_type"
Esin Karamanccb714b2019-11-29 15:02:06 +0000110 //EthDst constant
111 EthDst = "eth_dst"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700112 //TPID constant
113 TPID = "tpid"
114 //IPProto constant
115 IPProto = "ip_proto"
116 //InPort constant
117 InPort = "in_port"
118 //VlanVid constant
119 VlanVid = "vlan_vid"
120 //VlanPcp constant
121 VlanPcp = "vlan_pcp"
122
123 //UDPDst constant
124 UDPDst = "udp_dst"
125 //UDPSrc constant
126 UDPSrc = "udp_src"
127 //Ipv4Dst constant
128 Ipv4Dst = "ipv4_dst"
129 //Ipv4Src constant
130 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700131 //Metadata constant
132 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700133 //TunnelID constant
134 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700135 //Output constant
136 Output = "output"
Esin Karamanccb714b2019-11-29 15:02:06 +0000137 //GroupID constant
138 GroupID = "group_id"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700139 // Actions
140
141 //PopVlan constant
142 PopVlan = "pop_vlan"
143 //PushVlan constant
144 PushVlan = "push_vlan"
145 //TrapToHost constant
146 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400147 //MaxMeterBand constant
148 MaxMeterBand = 2
149 //VlanPCPMask contant
150 VlanPCPMask = 0xFF
151 //VlanvIDMask constant
152 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000153 //IntfID constant
154 IntfID = "intfId"
155 //OnuID constant
156 OnuID = "onuId"
157 //UniID constant
158 UniID = "uniId"
159 //PortNo constant
160 PortNo = "portNo"
161 //AllocID constant
162 AllocID = "allocId"
Esin Karamanccb714b2019-11-29 15:02:06 +0000163
164 //NoneOnuID constant
165 NoneOnuID = -1
166 //NoneUniID constant
167 NoneUniID = -1
168 //NoneGemPortID constant
169 NoneGemPortID = -1
Girish Gowdrafae935c2020-02-17 19:21:44 +0530170
171 // BinaryStringPrefix is binary string prefix
172 BinaryStringPrefix = "0b"
173 // BinaryBit1 is binary bit 1 expressed as a character
174 BinaryBit1 = '1'
manikkaraj kbf256be2019-03-25 00:13:48 +0530175)
176
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400177type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700178 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400179 gemPort uint32
180}
181
Girish Gowdra3d633032019-12-10 16:37:05 +0530182type pendingFlowDeleteKey struct {
183 intfID uint32
184 onuID uint32
185 uniID uint32
186}
187
188type tpLockKey struct {
189 intfID uint32
190 onuID uint32
191 uniID uint32
192}
193
Gamze Abakafee36392019-10-03 11:17:24 +0000194type schedQueue struct {
195 direction tp_pb.Direction
196 intfID uint32
197 onuID uint32
198 uniID uint32
199 tpID uint32
200 uniPort uint32
201 tpInst *tp.TechProfile
202 meterID uint32
203 flowMetadata *voltha.FlowMetadata
204}
205
Esin Karamanccb714b2019-11-29 15:02:06 +0000206type queueInfoBrief struct {
207 gemPortID uint32
208 servicePriority uint32
209}
210
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700211//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530212type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000213 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000214 deviceHandler *DeviceHandler
215 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000216 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530217 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
218 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
219 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
220 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530221 pendingFlowDelete sync.Map
222 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
Esin Karamanccb714b2019-11-29 15:02:06 +0000223 perUserFlowHandleLock *mapmutex.Mutex
224 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 +0530225}
226
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700227//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
npujarec5762e2020-01-01 14:08:48 +0530228func NewFlowManager(ctx context.Context, dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530229 log.Info("Initializing flow manager")
230 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530231 var err error
232 var idx uint32
233
manikkaraj kbf256be2019-03-25 00:13:48 +0530234 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530235 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000236 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530237 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530238 log.Error("Error while populating tech profile mgr\n")
239 return nil
240 }
William Kurkian740a09c2019-10-23 17:07:38 -0400241 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530242 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
243 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
244 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
245 ponPorts := rMgr.DevInfo.GetPonPorts()
246 //Load the onugem info cache from kv store on flowmanager start
247 for idx = 0; idx < ponPorts; idx++ {
npujarec5762e2020-01-01 14:08:48 +0530248 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(ctx, idx); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530249 log.Error("Failed to load onu gem info cache")
250 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530251 //Load flowID list per gem map per interface from the kvstore.
npujarec5762e2020-01-01 14:08:48 +0530252 flowMgr.loadFlowIDlistForGem(ctx, idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530253 }
254 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530255 flowMgr.pendingFlowDelete = sync.Map{}
256 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
Esin Karamanccb714b2019-11-29 15:02:06 +0000257 flowMgr.interfaceToMcastQueueMap = make(map[uint32]*queueInfoBrief)
258 //load interface to multicast queue map from kv store
npujarec5762e2020-01-01 14:08:48 +0530259 flowMgr.loadInterfaceToMulticastQueueMap(ctx)
manikkaraj kbf256be2019-03-25 00:13:48 +0530260 log.Info("Initialization of flow manager success!!")
261 return &flowMgr
262}
263
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700264func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700265 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400266 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700267 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700268 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400269 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700270 return uint64(flowID), nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000271 } else if direction == Multicast {
272 log.Debug("multicast flow, shifting id")
273 return 0x2<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400274 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +0530275 return 0, olterrors.NewErrInvalidValue(log.Fields{"direction": direction}, nil).Log()
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400276 }
277}
278
npujarec5762e2020-01-01 14:08:48 +0530279func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400280 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700281 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000282 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
283 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
284 if !ok {
285 flowIDList = []uint32{deviceFlow.FlowId}
286 }
287 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
288 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530289 // update the flowids for a gem to the KVstore
npujarec5762e2020-01-01 14:08:48 +0530290 f.resourceMgr.UpdateFlowIDsForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400291}
292
npujarec5762e2020-01-01 14:08:48 +0530293func (f *OpenOltFlowMgr) divideAndAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000294 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
295 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000296 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530297 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400298 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530299
Manikkaraj kb1d51442019-07-23 10:41:02 -0400300 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000301 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400302 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
303 // is because the flow is an NNI flow and there would be no onu resources associated with it
304 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400305 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400306 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530307 return
308 }
309
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530310 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400311 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530312
313 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
314 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
npujarec5762e2020-01-01 14:08:48 +0530315 allocID, gemPorts, TpInst = f.createTcontGemports(ctx, intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +0530316 if allocID == 0 || gemPorts == nil || TpInst == nil {
317 log.Error("alloc-id-gem-ports-tp-unavailable")
318 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
319 return
320 }
321 args := make(map[string]uint32)
322 args[IntfID] = intfID
323 args[OnuID] = onuID
324 args[UniID] = uniID
325 args[PortNo] = portNo
326 args[AllocID] = allocID
327
328 /* Flows can be added specific to gemport if p-bits are received.
329 * If no pbit mentioned then adding flows for all gemports
330 */
npujarec5762e2020-01-01 14:08:48 +0530331 f.checkAndAddFlow(ctx, args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
Girish Gowdra3d633032019-12-10 16:37:05 +0530332 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
333 } else {
334 log.Errorw("failed to acquire per user flow handle lock",
335 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400336 return
337 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530338}
339
salmansiddiqui7ac62132019-08-22 03:58:50 +0000340// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530341func (f *OpenOltFlowMgr) CreateSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400342
Gamze Abakafee36392019-10-03 11:17:24 +0000343 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
344 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
345 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400346
Gamze Abakafee36392019-10-03 11:17:24 +0000347 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000348 if err != nil {
349 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400350 }
351
352 /* Lets make a simple assumption that if the meter-id is present on the KV store,
353 * then the scheduler and queues configuration is applied on the OLT device
354 * in the given direction.
355 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000356
Manikkaraj kb1d51442019-07-23 10:41:02 -0400357 var SchedCfg *tp_pb.SchedulerConfig
npujarec5762e2020-01-01 14:08:48 +0530358 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400359 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000360 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 -0400361 return err
362 }
363 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000364 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400365 log.Debug("Scheduler already created for upstream")
366 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400367 }
Thomas Lee S94109f12020-03-03 16:39:29 +0530368 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800369 "unsupported": "meter-id",
370 "kv-store-meter-id": KvStoreMeter.MeterId,
371 "meter-id-in-flow": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400372 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000373
Gamze Abakafee36392019-10-03 11:17:24 +0000374 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000375
Gamze Abakafee36392019-10-03 11:17:24 +0000376 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000377 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000378 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000379 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400380 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000381
382 if err != nil {
383 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
384 return err
385 }
386
Manikkaraj kb1d51442019-07-23 10:41:02 -0400387 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000388 if sq.flowMetadata != nil {
389 for _, meter := range sq.flowMetadata.Meters {
390 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400391 meterConfig = meter
392 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
393 break
394 }
395 }
396 } else {
397 log.Error("Flow-metadata-is-not-present-in-flow")
398 }
399 if meterConfig == nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530400 return olterrors.NewErrNotFound("meterbands", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800401 "reason": "Could-not-get-meterbands-from-flowMetadata",
402 "flow-metadata": sq.flowMetadata,
403 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400404 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000405 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
Thomas Lee S94109f12020-03-03 16:39:29 +0530406 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800407 "reason": "Invalid-number-of-bands-in-meter",
408 "meterband-count": len(meterConfig.Bands),
409 "metabands": meterConfig.Bands,
410 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400411 }
412 cir := meterConfig.Bands[0].Rate
413 cbs := meterConfig.Bands[0].BurstSize
414 eir := meterConfig.Bands[1].Rate
415 ebs := meterConfig.Bands[1].BurstSize
416 pir := cir + eir
417 pbs := cbs + ebs
418 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
419
Gamze Abakafee36392019-10-03 11:17:24 +0000420 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400421
npujarec5762e2020-01-01 14:08:48 +0530422 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000423 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 -0400424 return err
425 }
426
salmansiddiqui7ac62132019-08-22 03:58:50 +0000427 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400428 * store the meter id on the KV store, for further reference.
429 */
npujarec5762e2020-01-01 14:08:48 +0530430 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 +0000431 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400432 return err
433 }
434 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
435 "Meter": meterConfig})
436 return nil
437}
438
npujarec5762e2020-01-01 14:08:48 +0530439func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000440
441 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
442
443 if err != nil {
444 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
445 return err
446 }
447
448 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530449 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000450 IntfId: sq.intfID, OnuId: sq.onuID,
451 UniId: sq.uniID, PortNo: sq.uniPort,
452 TrafficScheds: TrafficSched}); err != nil {
453 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
454 return err
455 }
456
457 // On receiving the CreateTrafficQueues request, the driver should create corresponding
458 // downstream queues.
459 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530460 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000461 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
462 UniId: sq.uniID, PortNo: sq.uniPort,
463 TrafficQueues: trafficQueues}); err != nil {
464 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
465 return err
466 }
467
Esin Karamanccb714b2019-11-29 15:02:06 +0000468 if sq.direction == tp_pb.Direction_DOWNSTREAM {
469 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
470 if len(multicastTrafficQueues) > 0 {
471 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
472 //assumed that there is only one queue per PON for the multicast service
473 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
474 //just put it in interfaceToMcastQueueMap to use for building group members
475 multicastQueuePerPonPort := multicastTrafficQueues[0]
476 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
477 gemPortID: multicastQueuePerPonPort.GemportId,
478 servicePriority: multicastQueuePerPonPort.Priority,
479 }
480 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530481 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000482 multicastQueuePerPonPort.GemportId,
483 multicastQueuePerPonPort.Priority)
484 }
485 }
486 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000487 return nil
488}
489
salmansiddiqui7ac62132019-08-22 03:58:50 +0000490// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530491func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400492
493 var Direction string
494 var SchedCfg *tp_pb.SchedulerConfig
495 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000496 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
497 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
498 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000499 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400500 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000501 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000502 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400503 Direction = "downstream"
504 }
505
Girish Kumar8f73fe02019-12-09 13:19:37 +0000506 if err != nil {
507 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
508 return err
509 }
510
npujarec5762e2020-01-01 14:08:48 +0530511 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400512 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000513 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400514 return err
515 }
516 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000517 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 -0400518 return nil
519 }
520 cir := KVStoreMeter.Bands[0].Rate
521 cbs := KVStoreMeter.Bands[0].BurstSize
522 eir := KVStoreMeter.Bands[1].Rate
523 ebs := KVStoreMeter.Bands[1].BurstSize
524 pir := cir + eir
525 pbs := cbs + ebs
526
527 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
528
Gamze Abakafee36392019-10-03 11:17:24 +0000529 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000530
531 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
532 if err != nil {
533 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
534 return err
535 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400536
npujarec5762e2020-01-01 14:08:48 +0530537 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000538 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
539 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400540 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000541 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400542 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400543 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000544 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530545 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000546 IntfId: sq.intfID, OnuId: sq.onuID,
547 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400548 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000549 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400550 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400551 }
552
salmansiddiqui7ac62132019-08-22 03:58:50 +0000553 log.Debug("Removed traffic schedulers successfully")
554
555 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400556 * delete the meter id on the KV store.
557 */
npujarec5762e2020-01-01 14:08:48 +0530558 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400559 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000560 log.Errorf("Failed to remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000561 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400562 }
563 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
564 return err
565}
566
Gamze Abakafee36392019-10-03 11:17:24 +0000567// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530568func (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 +0000569 var allocIDs []uint32
570 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530571 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530572 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000573 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000574
npujarec5762e2020-01-01 14:08:48 +0530575 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
576 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400577
578 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530579
580 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
581
Manikkaraj kb1d51442019-07-23 10:41:02 -0400582 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530583 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000584 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530585 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530586 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000587 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530588 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000589 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000590 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530591 }
npujarec5762e2020-01-01 14:08:48 +0530592 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530593 } else {
594 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530595 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530596 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400597 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000598 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
599 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530600 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400601 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000602 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400603 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530604 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400605 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000606 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
607 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530608 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400609 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000610 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400611 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530612 }
Gamze Abakafee36392019-10-03 11:17:24 +0000613
614 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000615 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000616 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400617 }
Gamze Abakafee36392019-10-03 11:17:24 +0000618
Girish Gowdra3d633032019-12-10 16:37:05 +0530619 if tpInstanceExists {
620 return allocID, gemPortIDs, techProfileInstance
621 }
622
623 allocIDs = appendUnique(allocIDs, allocID)
624 for _, gemPortID := range gemPortIDs {
625 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
626 }
627
Gamze Abakafee36392019-10-03 11:17:24 +0000628 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530629 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530630 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000631 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530632}
633
npujarec5762e2020-01-01 14:08:48 +0530634func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530635
636 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700637 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530638 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530639 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530640 log.Error("Errow while uploading allocID to KV store")
641 }
npujarec5762e2020-01-01 14:08:48 +0530642 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530643 log.Error("Errow while uploading GEMports to KV store")
644 }
npujarec5762e2020-01-01 14:08:48 +0530645 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530646 log.Error("Errow while uploading gemtopon map to KV store")
647 }
648 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400649 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530650 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400651 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530652}
653
654func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000655 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530656 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000657 for _, intfID := range techRange.IntfIds {
658 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400659 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000660 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530661 }
662 }
663 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400664 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
Thomas Lee S94109f12020-03-03 16:39:29 +0530665 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800666 "reason": "TP count does not match number of PON ports",
667 "tech-profile-count": tpCount,
668 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530669 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400670 log.Infow("Populated techprofile for ponports successfully",
671 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530672 return nil
673}
674
npujarec5762e2020-01-01 14:08:48 +0530675func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530676 portNo uint32, uplinkClassifier map[string]interface{},
677 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800678 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700679 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530680 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800681 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700682 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530683 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530684}
685
npujarec5762e2020-01-01 14:08:48 +0530686func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530687 portNo uint32, downlinkClassifier map[string]interface{},
688 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800689 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700690 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530691 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
692 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400693 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
694 if vlan, exists := downlinkClassifier[VlanVid]; exists {
695 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700696 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400697 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
698 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800699 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400700 }
701 }
702 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530703 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400704
Manikkaraj k884c1242019-04-11 16:26:42 +0530705 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700706 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400707 // vlan_vid is a uint32. must be type asserted as such or conversion fails
708 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530709 if ok {
710 downlinkAction[VlanVid] = dlClVid & 0xfff
711 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +0530712 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800713 "reason": "failed to convert VLANID classifier",
714 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530715 }
716
David K. Bainbridge794735f2020-02-11 21:01:37 -0800717 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700718 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530719}
720
npujarec5762e2020-01-01 14:08:48 +0530721func (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 +0530722 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800723 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530724 /* One of the OLT platform (Broadcom BAL) requires that symmetric
725 flows require the same flow_id to be used across UL and DL.
726 Since HSIA flow is the only symmetric flow currently, we need to
727 re-use the flow_id across both direction. The 'flow_category'
728 takes priority over flow_cookie to find any available HSIA_FLOW
729 id for the ONU.
730 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700731 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
732 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530733 "logicalFlow": *logicalFlow})
Girish Gowdrafae935c2020-02-17 19:21:44 +0530734 var vlanPbit uint32 = 0xff // means no pbit
Manikkaraj kb1d51442019-07-23 10:41:02 -0400735 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000736 vlanPbit = classifier[VlanPcp].(uint32)
737 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800738 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +0530739 log.Debugw("pbit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400740 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700741 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530742 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800743 log.Debug("flow-already-exists")
744 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530745 }
npujarec5762e2020-01-01 14:08:48 +0530746 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530747 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530748 return olterrors.NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530749 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800750 classifierProto, err := makeOpenOltClassifierField(classifier)
751 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530752 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530753 }
754 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800755 actionProto, err := makeOpenOltActionField(action)
756 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530757 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530758 }
759 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800760 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530761 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530762 return olterrors.NewErrNotFound("nni-interface-id",
David K. Bainbridge794735f2020-02-11 21:01:37 -0800763 log.Fields{
764 "classifier": classifier,
765 "action": action,
766 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530767 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700768 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
769 OnuId: int32(onuID),
770 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000771 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530772 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700773 AllocId: int32(allocID),
774 NetworkIntfId: int32(networkIntfID),
775 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530776 Classifier: classifierProto,
777 Action: actionProto,
778 Priority: int32(logicalFlow.Priority),
779 Cookie: logicalFlow.Cookie,
780 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800781 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530782 return olterrors.NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530783 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800784 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
785 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
786 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
787 flow.OnuId,
788 flow.UniId,
789 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530790 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800791 }
792 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530793}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000794
David K. Bainbridge794735f2020-02-11 21:01:37 -0800795func (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 +0530796
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530797 networkIntfID, err := getNniIntfID(classifier, action)
798 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530799 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800800 "classifier": classifier,
801 "action": action},
802 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530803 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530804
805 // Clear the action map
806 for k := range action {
807 delete(action, k)
808 }
809
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700810 action[TrapToHost] = true
811 classifier[UDPSrc] = uint32(68)
812 classifier[UDPDst] = uint32(67)
813 classifier[PacketTagType] = SingleTag
814 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530815
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700816 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530817 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530818 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800819 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530820 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530821
David K. Bainbridge794735f2020-02-11 21:01:37 -0800822 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 +0530823
824 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530825 return olterrors.NewErrNotFound("flow", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800826 "interface-id": intfID,
827 "gem-port": gemPortID,
828 "cookie": flowStoreCookie},
829 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530830 }
831
832 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
833
David K. Bainbridge794735f2020-02-11 21:01:37 -0800834 classifierProto, err := makeOpenOltClassifierField(classifier)
835 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530836 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530837 }
838 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800839 actionProto, err := makeOpenOltActionField(action)
840 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530841 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530842 }
843
David K. Bainbridge794735f2020-02-11 21:01:37 -0800844 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700845 OnuId: int32(onuID),
846 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530847 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700848 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700849 AllocId: int32(allocID),
850 NetworkIntfId: int32(networkIntfID),
851 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530852 Classifier: classifierProto,
853 Action: actionProto,
854 Priority: int32(logicalFlow.Priority),
855 Cookie: logicalFlow.Cookie,
856 PortNo: portNo}
857
David K. Bainbridge794735f2020-02-11 21:01:37 -0800858 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530859 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800860 }
861 log.Debug("DHCP UL flow added to device successfully")
862 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
863 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
864 dhcpFlow.OnuId,
865 dhcpFlow.UniId,
866 dhcpFlow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530867 return olterrors.NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530868 }
869
David K. Bainbridge794735f2020-02-11 21:01:37 -0800870 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530871}
872
Esin Karamanae41e2b2019-12-17 18:13:13 +0000873//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530874func (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 -0800875 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
876 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000877}
878
879//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530880func (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 -0800881 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000882
883 networkIntfID, err := getNniIntfID(classifier, action)
884 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530885 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800886 "classifier": classifier,
887 "action": action},
888 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000889 }
890
891 // Clear the action map
892 for k := range action {
893 delete(action, k)
894 }
895
896 action[TrapToHost] = true
897 classifier[PacketTagType] = SingleTag
898 delete(classifier, VlanVid)
899
900 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530901 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800902 log.Debug("Flow-exists-not-re-adding")
903 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000904 }
905
npujarec5762e2020-01-01 14:08:48 +0530906 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 +0000907
908 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530909 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800910 "interface-id": intfID,
911 "oni-id": onuID,
912 "cookie": flowStoreCookie,
913 "flow-type": flowType},
914 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000915 }
916
917 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
918
David K. Bainbridge794735f2020-02-11 21:01:37 -0800919 classifierProto, err := makeOpenOltClassifierField(classifier)
920 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530921 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000922 }
923 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800924 actionProto, err := makeOpenOltActionField(action)
925 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530926 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000927 }
928
David K. Bainbridge794735f2020-02-11 21:01:37 -0800929 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000930 OnuId: int32(onuID),
931 UniId: int32(uniID),
932 FlowId: flowID,
933 FlowType: Upstream,
934 AllocId: int32(allocID),
935 NetworkIntfId: int32(networkIntfID),
936 GemportId: int32(gemPortID),
937 Classifier: classifierProto,
938 Action: actionProto,
939 Priority: int32(logicalFlow.Priority),
940 Cookie: logicalFlow.Cookie,
941 PortNo: portNo}
942
David K. Bainbridge794735f2020-02-11 21:01:37 -0800943 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530944 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800945 }
946 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000947
David K. Bainbridge794735f2020-02-11 21:01:37 -0800948 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
949 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
950 flow.OnuId,
951 flow.UniId,
952 flow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530953 return olterrors.NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000954 }
955
David K. Bainbridge794735f2020-02-11 21:01:37 -0800956 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000957}
958
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700959// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Girish Gowdrafae935c2020-02-17 19:21:44 +0530960func (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 -0700961 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 +0530962
963 uplinkClassifier := make(map[string]interface{})
964 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530965
manikkaraj kbf256be2019-03-25 00:13:48 +0530966 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700967 uplinkClassifier[EthType] = uint32(EapEthType)
968 uplinkClassifier[PacketTagType] = SingleTag
969 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530970 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700971 uplinkAction[TrapToHost] = true
972 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530973 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800974 log.Debug("Flow-exists-not-re-adding")
975 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530976 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530977 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530978 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530979 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530980 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800981 "interface-id": intfID,
982 "onu-id": onuID,
983 "coookie": flowStoreCookie},
984 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530985 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700986 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530987
David K. Bainbridge794735f2020-02-11 21:01:37 -0800988 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
989 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530990 return olterrors.NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530991 }
992 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800993 actionProto, err := makeOpenOltActionField(uplinkAction)
994 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530995 return olterrors.NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530996 }
997 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800998 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530999 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301000 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001001 "classifier": classifier,
1002 "action": action},
1003 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301004 }
1005
David K. Bainbridge794735f2020-02-11 21:01:37 -08001006 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001007 OnuId: int32(onuID),
1008 UniId: int32(uniID),
1009 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001010 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001011 AllocId: int32(allocID),
1012 NetworkIntfId: int32(networkIntfID),
1013 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301014 Classifier: classifierProto,
1015 Action: actionProto,
1016 Priority: int32(logicalFlow.Priority),
1017 Cookie: logicalFlow.Cookie,
1018 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001019 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301020 return olterrors.NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001021 }
1022 log.Debug("EAPOL UL flow added to device successfully")
1023 flowCategory := "EAPOL"
1024 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1025 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1026 upstreamFlow.OnuId,
1027 upstreamFlow.UniId,
1028 upstreamFlow.FlowId,
1029 /* lowCategory, */
1030 flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301031 return olterrors.NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301032 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301033
manikkaraj kbf256be2019-03-25 00:13:48 +05301034 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001035 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301036}
1037
David K. Bainbridge794735f2020-02-11 21:01:37 -08001038func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001039 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001040
1041 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1042 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1043 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
Andrea Campanella7acc0b92020-02-14 09:20:49 +01001044 if vlanID != ReservedVlan {
1045 vid := vlanID & VlanvIDMask
Harsh Awasthiea45af72019-08-26 02:39:00 -04001046 classifier.OVid = vid
1047 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301048 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001049 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1050 vid := uint32(metadata)
1051 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001052 classifier.IVid = vid
1053 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301054 }
Girish Gowdrafae935c2020-02-17 19:21:44 +05301055 // Use VlanPCPMask (0xff) to signify NO PCP. Else use valid PCP (0 to 7)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001056 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Girish Gowdrafae935c2020-02-17 19:21:44 +05301057 classifier.OPbits = vlanPcp
1058 } else {
1059 classifier.OPbits = VlanPCPMask
manikkaraj kbf256be2019-03-25 00:13:48 +05301060 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001061 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1062 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1063 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1064 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001065 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001066 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1067 classifier.PktTagType = pktTagType
1068
1069 switch pktTagType {
1070 case SingleTag:
1071 case DoubleTag:
1072 case Untagged:
1073 default:
Thomas Lee S94109f12020-03-03 16:39:29 +05301074 return nil, olterrors.NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301075 }
1076 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001077 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301078}
1079
David K. Bainbridge794735f2020-02-11 21:01:37 -08001080func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001081 var actionCmd openoltpb2.ActionCmd
1082 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301083 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001084 if _, ok := actionInfo[PopVlan]; ok {
1085 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301086 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001087 } else if _, ok := actionInfo[PushVlan]; ok {
1088 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301089 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001090 } else if _, ok := actionInfo[TrapToHost]; ok {
1091 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301092 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05301093 return nil, olterrors.NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301094 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001095 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301096}
1097
Manikkaraj kb1d51442019-07-23 10:41:02 -04001098func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1099 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301100}
1101
Gamze Abakafee36392019-10-03 11:17:24 +00001102// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301103func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1104 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001105 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001106 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301107 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +00001108 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 +05301109 // return err
1110 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001111 }
1112 }
1113 return nil
1114}
1115
1116// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301117func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001118 if uniPortName == "" {
1119 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1120 }
npujarec5762e2020-01-01 14:08:48 +05301121 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001122 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1123 return err
1124 }
1125 return nil
1126}
1127
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001128func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301129 if len(classifier) == 0 { // should never happen
1130 log.Error("Invalid classfier object")
1131 return 0
1132 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301133 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301134 var jsonData []byte
1135 var flowString string
1136 var err error
1137 // TODO: Do we need to marshall ??
1138 if jsonData, err = json.Marshal(classifier); err != nil {
1139 log.Error("Failed to encode classifier")
1140 return 0
1141 }
1142 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001143 if gemPortID != 0 {
1144 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301145 }
1146 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001147 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301148 hash := big.NewInt(0)
1149 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301150 generatedHash := hash.Uint64()
1151 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1152 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301153}
1154
npujarec5762e2020-01-01 14:08:48 +05301155func (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 +05301156 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001157 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001158 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1159 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1160 */
1161 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001162 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001163 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001164 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001165 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001166 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301167 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001168 if existingFlows != nil {
1169 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001170 //for _, f := range *existingFlows {
1171 // flows = append(flows, f)
1172 //}
1173 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001174 }
1175 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 +05301176 return &flows
1177}
1178
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001179//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1180// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1181// var intfId uint32
1182// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1183// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1184// */
1185// if flow.AccessIntfId != -1 {
1186// intfId = uint32(flow.AccessIntfId)
1187// } else {
1188// intfId = uint32(flow.NetworkIntfId)
1189// }
1190// // Get existing flows matching flowid for given subscriber from KV store
1191// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1192// if existingFlows != nil {
1193// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1194// for _, f := range *existingFlows {
1195// flows = append(flows, f)
1196// }
1197// }
1198// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1199// return &flows
1200//}
1201
npujarec5762e2020-01-01 14:08:48 +05301202func (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 -04001203 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301204 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001205 log.Debug("Error while Storing flow into KV store")
1206 return err
1207 }
1208 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301209 return nil
1210}
1211
David K. Bainbridge794735f2020-02-11 21:01:37 -08001212func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001213
1214 var intfID uint32
1215 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1216 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1217 */
1218 if deviceFlow.AccessIntfId != -1 {
1219 intfID = uint32(deviceFlow.AccessIntfId)
1220 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001221 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001222 intfID = uint32(deviceFlow.NetworkIntfId)
1223 }
1224
manikkaraj kbf256be2019-03-25 00:13:48 +05301225 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1226 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001227
1228 st, _ := status.FromError(err)
1229 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001230 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001231 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301232 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001233
1234 if err != nil {
1235 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301236 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001237 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001238 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301239 if deviceFlow.GemportId != -1 {
1240 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301241 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301242 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301243 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001244 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001245}
1246
David K. Bainbridge794735f2020-02-11 21:01:37 -08001247func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001248 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1249 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1250 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001251 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1252 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1253 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001254 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001255 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001256 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001257 return err
serkant.uluderya245caba2019-09-24 23:15:29 -07001258
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001259 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001260 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001261 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301262}
1263
1264/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1265 //update core flows_proxy : flows_proxy.update('/', flows)
1266}
1267
1268func generateStoredId(flowId uint32, direction string)uint32{
1269
David K. Bainbridge82efc492019-09-04 09:57:11 -07001270 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301271 log.Debug("Upstream flow shifting flowid")
1272 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001273 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301274 log.Debug("Downstream flow not shifting flowid")
1275 return flowId
1276 }else{
1277 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1278 return flowId
1279 }
1280}
1281
1282*/
1283
David K. Bainbridge794735f2020-02-11 21:01:37 -08001284func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001285
1286 classifierInfo := make(map[string]interface{})
1287 actionInfo := make(map[string]interface{})
1288
1289 classifierInfo[EthType] = uint32(LldpEthType)
1290 classifierInfo[PacketTagType] = Untagged
1291 actionInfo[TrapToHost] = true
1292
1293 // LLDP flow is installed to trap LLDP packets on the NNI port.
1294 // We manage flow_id resource pool on per PON port basis.
1295 // Since this situation is tricky, as a hack, we pass the NNI port
1296 // index (network_intf_id) as PON port Index for the flow_id resource
1297 // pool. Also, there is no ONU Id available for trapping LLDP packets
1298 // on NNI port, use onu_id as -1 (invalid)
1299 // ****************** CAVEAT *******************
1300 // This logic works if the NNI Port Id falls within the same valid
1301 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1302 // we need to have a re-look at this.
1303 // *********************************************
1304
1305 var onuID = -1
1306 var uniID = -1
1307 var gemPortID = -1
1308
David K. Bainbridge794735f2020-02-11 21:01:37 -08001309 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1310 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301311 return olterrors.NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001312 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001313 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301314 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001315 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001316 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001317 }
npujarec5762e2020-01-01 14:08:48 +05301318 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001319
1320 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301321 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001322 "interface-id": networkInterfaceID,
1323 "onu-id": onuID,
1324 "uni-id": uniID,
1325 "gem-port-id": gemPortID,
1326 "cookie": flowStoreCookie},
1327 err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001328 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001329 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1330 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301331 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001332 }
1333 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001334 actionProto, err := makeOpenOltActionField(actionInfo)
1335 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301336 return olterrors.NewErrInvalidValue(log.Fields{"action": actionInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001337 }
1338 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1339
1340 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1341 OnuId: int32(onuID), // OnuId not required
1342 UniId: int32(uniID), // UniId not used
1343 FlowId: flowID,
1344 FlowType: Downstream,
1345 NetworkIntfId: int32(networkInterfaceID),
1346 GemportId: int32(gemPortID),
1347 Classifier: classifierProto,
1348 Action: actionProto,
1349 Priority: int32(flow.Priority),
1350 Cookie: flow.Cookie,
1351 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001352 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301353 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001354 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001355 log.Debug("LLDP trap on NNI flow added to device successfully")
1356 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1357 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1358 int32(onuID),
1359 int32(uniID),
1360 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301361 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001362 }
1363 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301364}
1365
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301366func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001367 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1368}
1369
1370//getOnuChildDevice to fetch onu
1371func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1372 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1373 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001374 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1375 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301376 return nil, olterrors.NewErrNotFound("onu", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001377 "interface-id": parentPortNo,
1378 "onu-id": onuID},
1379 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301380 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301381 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1382 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301383}
1384
1385func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001386 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301387 return nil
1388}
1389
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001390func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1391 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301392}
1393
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001394func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001395 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001396 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001397 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001398 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001399}
1400
Girish Gowdra6b130582019-11-20 16:45:20 +05301401func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1402 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1403 if err != nil {
1404 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1405 return err
1406 }
1407
1408 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1409 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1410 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1411 delGemPortMsg,
1412 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1413 f.deviceHandler.deviceType,
1414 onuDevice.Type,
1415 onuDevice.Id,
1416 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1417 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1418 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1419 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1420 return sendErr
1421 }
1422 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1423 return nil
1424}
1425
1426func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1427 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1428 if err != nil {
1429 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1430 return err
1431 }
1432
1433 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1434 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1435 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1436 delTcontMsg,
1437 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1438 f.deviceHandler.deviceType,
1439 onuDevice.Type,
1440 onuDevice.Id,
1441 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1442 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1443 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1444 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1445 return sendErr
1446 }
1447 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1448 return nil
1449}
1450
Girish Gowdra3d633032019-12-10 16:37:05 +05301451func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1452 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1453 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1454 if val.(int) > 0 {
1455 pnFlDels := val.(int) - 1
1456 if pnFlDels > 0 {
1457 log.Debugw("flow delete succeeded, more pending",
1458 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1459 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1460 } else {
1461 log.Debugw("all pending flow deletes handled, removing entry from map",
1462 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1463 f.pendingFlowDelete.Delete(pnFlDelKey)
1464 }
1465 }
1466 } else {
1467 log.Debugw("no pending delete flows found",
1468 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1469
1470 }
1471
1472}
1473
Girish Gowdrac3037402020-01-22 20:29:53 +05301474// Once the gemport is released for a given onu, it also has to be cleared from local cache
1475// which was used for deriving the gemport->logicalPortNo during packet-in.
1476// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1477// is conveyed to ONOS during packet-in OF message.
1478func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1479 f.lockCache.Lock()
1480 defer f.lockCache.Unlock()
1481 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001482 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301483 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001484 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301485 // If the gemport is found, delete it from local cache.
1486 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001487 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1488 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301489 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001490 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301491 break
1492 }
1493 }
1494 break
1495 }
1496 }
1497}
1498
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301499//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301500func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301501 gemPortID int32, flowID uint32, flowDirection string,
1502 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001503
Chaitrashree G S90a17952019-11-14 21:51:21 -05001504 tpID, err := getTpIDFromFlow(flow)
1505 if err != nil {
1506 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1507 return err
1508 }
Gamze Abakafee36392019-10-03 11:17:24 +00001509
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001510 if len(updatedFlows) >= 0 {
1511 // There are still flows referencing the same flow_id.
1512 // So the flow should not be freed yet.
1513 // For ex: Case of HSIA where same flow is shared
1514 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301515 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001516 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301517 // Do this for subscriber flows only (not trap from NNI flows)
1518 if onuID != -1 && uniID != -1 {
1519 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1520 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1521 log.Debugw("creating entry for pending flow delete",
1522 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1523 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1524 } else {
1525 pnFlDels := val.(int) + 1
1526 log.Debugw("updating flow delete entry",
1527 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1528 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1529 }
1530
1531 defer f.deletePendingFlows(Intf, onuID, uniID)
1532 }
1533
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301534 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301535 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001536
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301537 uni := getUniPortPath(Intf, onuID, uniID)
1538 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001539 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301540 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001541 if err != nil { // This should not happen, something wrong in KV backend transaction
1542 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301543 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001544 }
1545 if techprofileInst == nil {
1546 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301547 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001548 }
1549
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301550 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001551 if f.isGemPortUsedByAnotherFlow(gemPK) {
1552 flowIDs := f.flowsUsedByGemPort[gemPK]
1553 for i, flowIDinMap := range flowIDs {
1554 if flowIDinMap == flowID {
1555 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301556 // everytime flowsUsedByGemPort cache is updated the same should be updated
1557 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001558 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301559 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001560 break
1561 }
1562 }
1563 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301564 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001565 }
Gamze Abakafee36392019-10-03 11:17:24 +00001566 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301567 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001568 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1569 // 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 +05301570 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301571 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001572 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301573 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1574 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001575 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301576 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1577 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001578 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301579 // Delete the gem port on the ONU.
1580 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1581 log.Errorw("error processing delete gem-port towards onu",
1582 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1583 }
Gamze Abakafee36392019-10-03 11:17:24 +00001584
npujarec5762e2020-01-01 14:08:48 +05301585 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001586 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301587 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1588 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1589 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1590 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1591 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301592 // Delete the TCONT on the ONU.
1593 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1594 log.Errorw("error processing delete tcont towards onu",
1595 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1596 }
Gamze Abakafee36392019-10-03 11:17:24 +00001597 }
1598 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001599 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301600 return nil
1601}
1602
David K. Bainbridge794735f2020-02-11 21:01:37 -08001603// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301604func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301605
1606 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001607
1608 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301609 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001610 return
1611 }
1612
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301613 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301614 classifierInfo := make(map[string]interface{})
1615
1616 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1617 if err != nil {
1618 log.Error(err)
1619 return
1620 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301621
David K. Bainbridge794735f2020-02-11 21:01:37 -08001622 onuID := int32(onu)
1623 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301624
1625 for _, field := range flows.GetOfbFields(flow) {
1626 if field.Type == flows.IP_PROTO {
1627 classifierInfo[IPProto] = field.GetIpProto()
1628 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1629 }
1630 }
1631 log.Debugw("Extracted access info from flow to be deleted",
1632 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1633
1634 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1635 onuID = -1
1636 uniID = -1
1637 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001638 Intf, err = IntfIDFromNniPortNum(inPort)
1639 if err != nil {
1640 log.Errorw("invalid-in-port-number",
1641 log.Fields{
1642 "port-number": inPort,
1643 "error": err})
1644 return
1645 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301646 }
npujarec5762e2020-01-01 14:08:48 +05301647 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001648 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301649 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301650 if flowInfo == nil {
1651 log.Debugw("No FlowInfo found found in KV store",
1652 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1653 return
1654 }
1655 updatedFlows = nil
1656 for _, flow := range *flowInfo {
1657 updatedFlows = append(updatedFlows, flow)
1658 }
1659
1660 for i, storedFlow := range updatedFlows {
1661 if flow.Id == storedFlow.LogicalFlowID {
1662 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1663 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001664 // DKB
1665 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1666 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1667 return
1668 }
1669 log.Debug("Flow removed from device successfully")
1670 //Remove the Flow from FlowInfo
1671 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1672 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1673 flowID, flowDirection, portNum, updatedFlows); err != nil {
1674 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301675 return
1676 }
1677 }
1678 }
1679 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001680}
1681
Esin Karamanccb714b2019-11-29 15:02:06 +00001682//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1683// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301684func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001685 classifierInfo := make(map[string]interface{})
1686 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301687 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001688
1689 if err != nil {
1690 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1691 return
1692 }
1693
David K. Bainbridge794735f2020-02-11 21:01:37 -08001694 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1695 if err != nil {
1696 // DKB
1697 log.Errorw("invalid-in-port-number",
1698 log.Fields{
1699 "port-number": inPort,
1700 "error": err})
1701 return
1702 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001703 var onuID = int32(NoneOnuID)
1704 var uniID = int32(NoneUniID)
1705 var flowID uint32
1706 var updatedFlows []rsrcMgr.FlowInfo
1707
npujarec5762e2020-01-01 14:08:48 +05301708 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001709
1710 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301711 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001712 if flowInfo == nil {
1713 log.Debugw("No multicast FlowInfo found in the KV store",
1714 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1715 continue
1716 }
1717 updatedFlows = nil
1718 for _, flow := range *flowInfo {
1719 updatedFlows = append(updatedFlows, flow)
1720 }
1721 for i, storedFlow := range updatedFlows {
1722 if flow.Id == storedFlow.LogicalFlowID {
1723 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1724 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1725 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001726 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1727 // DKB
1728 log.Errorw("failed-to-remove-multicast-flow",
1729 log.Fields{
1730 "flow-id": flow.Id,
1731 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001732 return
1733 }
1734 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1735 //Remove the Flow from FlowInfo
1736 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301737 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001738 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1739 return
1740 }
1741 //release flow id
1742 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301743 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001744 }
1745 }
1746 }
1747}
1748
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001749//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301750func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001751 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301752 var direction string
1753 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001754
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301755 for _, action := range flows.GetActions(flow) {
1756 if action.Type == flows.OUTPUT {
1757 if out := action.GetOutput(); out != nil {
1758 actionInfo[Output] = out.GetPort()
1759 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1760 } else {
1761 log.Error("Invalid output port in action")
1762 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001763 }
1764 }
1765 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001766
1767 if flows.HasGroup(flow) {
1768 direction = Multicast
1769 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301770 direction = Upstream
1771 } else {
1772 direction = Downstream
1773 }
npujarec5762e2020-01-01 14:08:48 +05301774 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301775
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001776 return
1777}
1778
Girish Gowdra3d633032019-12-10 16:37:05 +05301779func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1780 uniID uint32, ch chan bool) {
1781 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1782 for {
1783 select {
1784 case <-time.After(20 * time.Millisecond):
1785 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1786 log.Debug("pending flow deletes completed")
1787 ch <- true
1788 return
1789 }
1790 case <-ctx.Done():
1791 log.Error("flow delete wait handler routine canceled")
1792 return
1793 }
1794 }
1795}
1796
Esin Karamanae41e2b2019-12-17 18:13:13 +00001797//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1798func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1799 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1800 if ethType, ok := classifierInfo[EthType]; ok {
1801 if ethType.(uint32) == IPv4EthType {
1802 if ipProto, ok := classifierInfo[IPProto]; ok {
1803 if ipProto.(uint32) == IgmpProto {
1804 return true
1805 }
1806 }
1807 }
1808 }
1809 }
1810 return false
1811}
1812
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001813// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301814// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301815func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001816 classifierInfo := make(map[string]interface{})
1817 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001818 var UsMeterID uint32
1819 var DsMeterID uint32
1820
1821 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001822 formulateClassifierInfoFromFlow(classifierInfo, flow)
1823
1824 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1825 if err != nil {
1826 // Error logging is already done in the called function
1827 // So just return in case of error
1828 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301829 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001830
Esin Karamanccb714b2019-11-29 15:02:06 +00001831 if flows.HasGroup(flow) {
1832 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301833 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001834 return
1835 }
1836
manikkaraj k17652a72019-05-06 09:06:36 -04001837 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001838 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1839 if err != nil {
1840 // error if any, already logged in the called function
1841 return
manikkaraj k17652a72019-05-06 09:06:36 -04001842 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001843
David K. Bainbridge82efc492019-09-04 09:57:11 -07001844 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1845 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001846
Humera Kouser94d7a842019-08-25 19:04:32 -04001847 if ethType, ok := classifierInfo[EthType]; ok {
1848 if ethType.(uint32) == LldpEthType {
1849 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301850 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001851 return
1852 }
1853 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001854 if ipProto, ok := classifierInfo[IPProto]; ok {
1855 if ipProto.(uint32) == IPProtoDhcp {
1856 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301857 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001858 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301859 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001860 return
1861 }
1862 }
1863 }
1864 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001865 if isIgmpTrapDownstreamFlow(classifierInfo) {
1866 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301867 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001868 return
1869 }
A R Karthick1f85b802019-10-11 05:06:05 +00001870
1871 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301872 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001873
Chaitrashree G S90a17952019-11-14 21:51:21 -05001874 TpID, err := getTpIDFromFlow(flow)
1875 if err != nil {
1876 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1877 return
1878 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001879 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001880 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001881 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001882 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1883 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001884 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001885 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1886
1887 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301888
1889 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1890 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1891 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 +05301892 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301893 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301894 pendingFlowDelComplete := make(chan bool)
1895 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1896 select {
1897 case <-pendingFlowDelComplete:
1898 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301899 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301900
1901 case <-time.After(10 * time.Second):
1902 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1903 }
1904 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001905}
1906
Esin Karamanccb714b2019-11-29 15:02:06 +00001907// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001908func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001909 classifierInfo[PacketTagType] = DoubleTag
1910 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1911
npujarec5762e2020-01-01 14:08:48 +05301912 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001913 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301914 return olterrors.NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001915 }
1916 //replace ipDst with ethDst
1917 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1918 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1919 // replace ipv4_dst classifier with eth_dst
1920 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1921 delete(classifierInfo, Ipv4Dst)
1922 delete(classifierInfo, EthType)
1923 classifierInfo[EthDst] = multicastMac
1924 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1925 }
1926
David K. Bainbridge794735f2020-02-11 21:01:37 -08001927 onuID := NoneOnuID
1928 uniID := NoneUniID
1929 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001930
David K. Bainbridge794735f2020-02-11 21:01:37 -08001931 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1932 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301933 return olterrors.NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001934 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001935
David K. Bainbridge794735f2020-02-11 21:01:37 -08001936 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301937 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001938 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1939 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001940 }
npujarec5762e2020-01-01 14:08:48 +05301941 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001942 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301943 return olterrors.NewErrNotFound("multicast-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001944 "interface-id": networkInterfaceID,
1945 "onu-id": onuID,
1946 "uni-id": uniID,
1947 "gem-port-id": gemPortID,
1948 "cookie": flowStoreCookie},
1949 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001950 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001951 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1952 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301953 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001954 }
1955 groupID := actionInfo[GroupID].(uint32)
1956 multicastFlow := openoltpb2.Flow{
1957 FlowId: flowID,
1958 FlowType: Multicast,
1959 NetworkIntfId: int32(networkInterfaceID),
1960 GroupId: groupID,
1961 Classifier: classifierProto,
1962 Priority: int32(flow.Priority),
1963 Cookie: flow.Cookie}
1964
David K. Bainbridge794735f2020-02-11 21:01:37 -08001965 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301966 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001967 }
1968 log.Debug("multicast flow added to device successfully")
1969 //get cached group
1970 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1971 if err == nil {
1972 //calling groupAdd to set group members after multicast flow creation
1973 if f.ModifyGroup(ctx, group) {
1974 //cached group can be removed now
1975 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001976 }
1977 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001978
1979 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1980 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1981 int32(onuID),
1982 int32(uniID),
1983 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301984 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001985 }
1986 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001987}
1988
1989//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301990func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001991 if _, ok := classifierInfo[InPort]; ok {
1992 return classifierInfo[InPort].(uint32), nil
1993 }
1994 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301995 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001996 if e == nil && len(nniPorts) > 0 {
1997 return nniPorts[0], nil
1998 }
Thomas Lee S94109f12020-03-03 16:39:29 +05301999 return 0, olterrors.NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002000}
2001
2002// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05302003func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00002004 log.Infow("add-group", log.Fields{"group": group})
2005 if group == nil {
2006 log.Warn("skipping nil group")
2007 return
2008 }
2009
2010 groupToOlt := openoltpb2.Group{
2011 GroupId: group.Desc.GroupId,
2012 Command: openoltpb2.Group_SET_MEMBERS,
2013 Action: f.buildGroupAction(),
2014 }
2015
2016 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302017 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002018 if err != nil {
2019 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
2020 return
2021 }
2022 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302023 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002024 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
2025 } else {
2026 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2027 }
2028}
2029
2030//buildGroupAction creates and returns a group action
2031func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2032 var actionCmd openoltpb2.ActionCmd
2033 var action openoltpb2.Action
2034 action.Cmd = &actionCmd
2035 //pop outer vlan
2036 action.Cmd.RemoveOuterTag = true
2037 return &action
2038}
2039
2040// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05302041func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00002042 log.Infow("modify-group", log.Fields{"group": group})
2043 if group == nil || group.Desc == nil {
2044 log.Warn("cannot modify group; group is nil")
2045 return false
2046 }
2047
2048 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2049 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302050 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002051
2052 if err != nil {
2053 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2054 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2055 return false
2056 }
2057
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002058 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002059 if groupExists {
2060 // group already exists
2061 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002062 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002063 } else {
2064 current = f.buildGroup(group.Desc.GroupId, nil)
2065 }
2066
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002067 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2068 // get members to be added
2069 membersToBeAdded := f.findDiff(current, new)
2070 // get members to be removed
2071 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002072
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002073 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2074 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002075
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002076 groupToOlt := openoltpb2.Group{
2077 GroupId: group.Desc.GroupId,
2078 }
2079 var added, removed = true, true
2080 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2081 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2082 groupToOlt.Members = membersToBeAdded
2083 //execute addMembers
2084 added = f.callGroupAddRemove(&groupToOlt)
2085 }
2086 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2087 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2088 groupToOlt.Members = membersToBeRemoved
2089 //execute removeMembers
2090 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002091 }
2092
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002093 //save the modified group
2094 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302095 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002096 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2097 }
2098 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002099 } else {
2100 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2101 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002102 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002103 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002104}
2105
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002106//callGroupAddRemove performs add/remove buckets operation for the indicated group
2107func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2108 if err := f.performGroupOperation(group); err != nil {
2109 st, _ := status.FromError(err)
2110 //ignore already exists error code
2111 if st.Code() != codes.AlreadyExists {
2112 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002113 }
2114 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002115 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002116}
2117
2118//findDiff compares group members and finds members which only exists in groups2
2119func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2120 var members []*openoltpb2.GroupMember
2121 for _, bucket := range group2.Members {
2122 if !f.contains(group1.Members, bucket) {
2123 // bucket does not exist and must be added
2124 members = append(members, bucket)
2125 }
2126 }
2127 return members
2128}
2129
2130//contains returns true if the members list contains the given member; false otherwise
2131func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2132 for _, groupMember := range members {
2133 if groupMember.InterfaceId == member.InterfaceId {
2134 return true
2135 }
2136 }
2137 return false
2138}
2139
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002140//performGroupOperation call performGroupOperation operation of openolt proto
2141func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002142 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2143 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2144 if err != nil {
2145 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2146 }
2147 return err
2148}
2149
2150//buildGroup build openoltpb2.Group from given group id and bucket list
2151func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2152 group := openoltpb2.Group{
2153 GroupId: groupID}
2154 // create members of the group
2155 if buckets != nil {
2156 for _, ofBucket := range buckets {
2157 member := f.buildMember(ofBucket)
2158 if member != nil && !f.contains(group.Members, member) {
2159 group.Members = append(group.Members, member)
2160 }
2161 }
2162 }
2163 return &group
2164}
2165
2166//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2167func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2168 var outPort uint32
2169 outPortFound := false
2170 for _, ofAction := range ofBucket.Actions {
2171 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2172 outPort = ofAction.GetOutput().Port
2173 outPortFound = true
2174 }
2175 }
2176
2177 if !outPortFound {
2178 log.Debugw("bucket skipped since no out port found in it",
2179 log.Fields{"ofBucket": ofBucket})
2180 return nil
2181 }
2182 interfaceID := IntfIDFromUniPortNum(outPort)
2183 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2184 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2185 member := openoltpb2.GroupMember{
2186 InterfaceId: interfaceID,
2187 InterfaceType: openoltpb2.GroupMember_PON,
2188 GemPortId: groupInfo.gemPortID,
2189 Priority: groupInfo.servicePriority,
2190 }
2191 //add member to the group
2192 return &member
2193 }
2194 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2195 log.Fields{"ofBucket": ofBucket})
2196 return nil
2197}
2198
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002199//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002200func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002201
2202 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302203 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002204 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302205 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302206 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302207 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002208
Manikkaraj kb1d51442019-07-23 10:41:02 -04002209 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002210 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002211 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2212 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2213 tpDownloadMsg,
2214 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2215 f.deviceHandler.deviceType,
2216 onuDevice.Type,
2217 onuDevice.Id,
2218 onuDevice.ProxyAddress.DeviceId, "")
2219 if sendErr != nil {
2220 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2221 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2222 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2223 return sendErr
2224 }
2225 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302226 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302227}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002228
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302229//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302230func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302231
2232 f.lockCache.Lock()
2233 defer f.lockCache.Unlock()
2234 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2235 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002236 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2237 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302238 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2239 return
2240 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002241 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2242}
2243
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302244//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302245func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302246 f.lockCache.Lock()
2247 defer f.lockCache.Unlock()
2248 onugem := f.onuGemInfo[intfID]
2249 // update the gem to the local cache as well as to kv strore
2250 for idx, onu := range onugem {
2251 if onu.OnuID == onuID {
2252 // check if gem already exists , else update the cache and kvstore
2253 for _, gem := range onu.GemPorts {
2254 if gem == gemPort {
2255 log.Debugw("Gem already in cache, no need to update cache and kv store",
2256 log.Fields{"gem": gemPort})
2257 return
2258 }
2259 }
2260 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2261 f.onuGemInfo[intfID] = onugem
2262 }
2263 }
npujarec5762e2020-01-01 14:08:48 +05302264 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302265 if err != nil {
2266 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002267 return
2268 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002269}
2270
2271// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002272
2273//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2274func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302275
2276 f.lockCache.Lock()
2277 defer f.lockCache.Unlock()
2278
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002279 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 +05302280 // get onuid from the onugem info cache
2281 onugem := f.onuGemInfo[intfID]
2282 for _, onu := range onugem {
2283 for _, gem := range onu.GemPorts {
2284 if gem == gemPortID {
2285 return onu.OnuID, nil
2286 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002287 }
2288 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302289 return uint32(0), olterrors.NewErrNotFound("onu-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002290 "serial-number": serialNumber,
2291 "interface-id": intfID,
2292 "gem-port-id": gemPortID},
2293 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002294}
2295
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002296//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302297func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002298 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002299 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002300 var err error
2301
2302 if packetIn.IntfType == "pon" {
2303 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002304 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002305 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2306 return logicalPortNum, err
2307 }
2308 if packetIn.PortNo != 0 {
2309 logicalPortNum = packetIn.PortNo
2310 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002311 uniID := uint32(0) // FIXME - multi-uni support
2312 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002313 }
2314 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302315 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002316 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002317 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002318 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002319 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2320 "logicalPortNum": logicalPortNum,
2321 "IntfType": packetIn.IntfType,
2322 "packet": hex.EncodeToString(packetIn.Pkt),
2323 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002324 return logicalPortNum, nil
2325}
2326
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002327//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302328func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002329 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002330 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302331
2332 f.lockCache.Lock()
2333 defer f.lockCache.Unlock()
2334 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2335
2336 gemPortID, ok := f.packetInGemPort[pktInkey]
2337 if ok {
2338 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2339 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002340 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302341 //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 +05302342 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302343 if err == nil {
2344 if gemPortID != 0 {
2345 f.packetInGemPort[pktInkey] = gemPortID
2346 log.Debugw("Found gem port from kv store and updating cache with gemport",
2347 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2348 return gemPortID, nil
2349 }
2350 }
2351 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2352 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002353}
2354
npujarec5762e2020-01-01 14:08:48 +05302355func installFlowOnAllGemports(ctx context.Context,
2356 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002357 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002358 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302359 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302360 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302361 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302362 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002363 args map[string]uint32,
2364 classifier map[string]interface{}, action map[string]interface{},
2365 logicalFlow *ofp.OfpFlowStats,
2366 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302367 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002368 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002369 vlanID ...uint32) {
2370 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302371
2372 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2373 var gemPortID uint32
2374 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2375 // We need to trim prefix "0b", before further processing
2376 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2377 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2378 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2379 // If a particular character in the string is set to '1', identify the index of this character from
2380 // the LSB position which marks the PCP bit consumed by the given gem port.
2381 // This PCP bit now becomes a classifier in the flow.
2382 if pbitSet == BinaryBit1 {
2383 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2384 gemPortID = gemPortAttribute.GemportID
2385 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2386 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2387 } else if FlowType == EapolFlow {
2388 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2389 } else {
2390 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2391 return
2392 }
2393 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002394 }
2395 }
2396}
2397
David K. Bainbridge794735f2020-02-11 21:01:37 -08002398func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002399 log.Debug("Adding trap-dhcp-of-nni-flow")
2400 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002401 classifier[PacketTagType] = DoubleTag
2402 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002403 /* We manage flowId resource pool on per PON port basis.
2404 Since this situation is tricky, as a hack, we pass the NNI port
2405 index (network_intf_id) as PON port Index for the flowId resource
2406 pool. Also, there is no ONU Id available for trapping DHCP packets
2407 on NNI port, use onu_id as -1 (invalid)
2408 ****************** CAVEAT *******************
2409 This logic works if the NNI Port Id falls within the same valid
2410 range of PON Port Ids. If this doesn't work for some OLT Vendor
2411 we need to have a re-look at this.
2412 *********************************************
2413 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002414 onuID := -1
2415 uniID := -1
2416 gemPortID := -1
2417 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002418 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302419 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302420 return olterrors.NewErrNotFound("nni-intreface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002421 "classifier": classifier,
2422 "action": action},
2423 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302424 }
2425
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002426 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302427 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002428 log.Debug("Flow-exists-not-re-adding")
2429 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002430 }
npujarec5762e2020-01-01 14:08:48 +05302431 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002432 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302433 return olterrors.NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002434 "interface-id": networkInterfaceID,
2435 "onu-id": onuID,
2436 "uni-id": uniID,
2437 "gem-port-id": gemPortID,
2438 "cookie": flowStoreCookie},
2439 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002440 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002441 classifierProto, err := makeOpenOltClassifierField(classifier)
2442 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302443 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002444 }
2445 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002446 actionProto, err := makeOpenOltActionField(action)
2447 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302448 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002449 }
2450 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002451 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2452 OnuId: int32(onuID), // OnuId not required
2453 UniId: int32(uniID), // UniId not used
2454 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002455 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002456 AllocId: int32(allocID), // AllocId not used
2457 NetworkIntfId: int32(networkInterfaceID),
2458 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002459 Classifier: classifierProto,
2460 Action: actionProto,
2461 Priority: int32(logicalFlow.Priority),
2462 Cookie: logicalFlow.Cookie,
2463 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002464 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302465 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002466 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002467 log.Debug("DHCP trap on NNI flow added to device successfully")
2468 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2469 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2470 int32(onuID),
2471 int32(uniID),
2472 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302473 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08002474 }
2475 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002476}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002477
Esin Karamanae41e2b2019-12-17 18:13:13 +00002478//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2479func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2480 var packetType string
2481 ovid, ivid := false, false
2482 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2483 vid := vlanID & VlanvIDMask
2484 if vid != ReservedVlan {
2485 ovid = true
2486 }
2487 }
2488 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2489 vid := uint32(metadata)
2490 if vid != ReservedVlan {
2491 ivid = true
2492 }
2493 }
2494 if ovid && ivid {
2495 packetType = DoubleTag
2496 } else if !ovid && !ivid {
2497 packetType = Untagged
2498 } else {
2499 packetType = SingleTag
2500 }
2501 return packetType
2502}
2503
2504//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002505func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002506 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2507 action := make(map[string]interface{})
2508 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2509 action[TrapToHost] = true
2510 /* We manage flowId resource pool on per PON port basis.
2511 Since this situation is tricky, as a hack, we pass the NNI port
2512 index (network_intf_id) as PON port Index for the flowId resource
2513 pool. Also, there is no ONU Id available for trapping packets
2514 on NNI port, use onu_id as -1 (invalid)
2515 ****************** CAVEAT *******************
2516 This logic works if the NNI Port Id falls within the same valid
2517 range of PON Port Ids. If this doesn't work for some OLT Vendor
2518 we need to have a re-look at this.
2519 *********************************************
2520 */
2521 onuID := -1
2522 uniID := -1
2523 gemPortID := -1
2524 allocID := -1
2525 networkInterfaceID, err := getNniIntfID(classifier, action)
2526 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302527 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002528 "classifier": classifier,
2529 "action": action},
2530 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002531 }
2532 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302533 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002534 log.Debug("igmp-flow-exists-not-re-adding")
2535 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002536 }
npujarec5762e2020-01-01 14:08:48 +05302537 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002538 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302539 return olterrors.NewErrNotFound("igmp-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002540 "interface-id": networkInterfaceID,
2541 "onu-id": onuID,
2542 "uni-id": uniID,
2543 "gem-port-id": gemPortID,
2544 "cookie": flowStoreCookie},
2545 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002546 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002547 classifierProto, err := makeOpenOltClassifierField(classifier)
2548 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302549 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002550 }
2551 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002552 actionProto, err := makeOpenOltActionField(action)
2553 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302554 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002555 }
2556 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2557 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2558 OnuId: int32(onuID), // OnuId not required
2559 UniId: int32(uniID), // UniId not used
2560 FlowId: flowID,
2561 FlowType: Downstream,
2562 AllocId: int32(allocID), // AllocId not used
2563 NetworkIntfId: int32(networkInterfaceID),
2564 GemportId: int32(gemPortID), // GemportId not used
2565 Classifier: classifierProto,
2566 Action: actionProto,
2567 Priority: int32(logicalFlow.Priority),
2568 Cookie: logicalFlow.Cookie,
2569 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002570 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302571 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002572 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002573 log.Debug("IGMP Trap on NNI flow added to device successfully")
2574 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2575 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2576 int32(onuID),
2577 int32(uniID),
2578 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302579 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08002580 }
2581 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002582}
2583
salmansiddiqui7ac62132019-08-22 03:58:50 +00002584func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2585 if MeterID == 0 { // This should never happen
Thomas Lee S94109f12020-03-03 16:39:29 +05302586 return "", olterrors.NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002587 }
2588 if Dir == tp_pb.Direction_UPSTREAM {
2589 return "upstream", nil
2590 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2591 return "downstream", nil
2592 }
2593 return "", nil
2594}
2595
npujarec5762e2020-01-01 14:08:48 +05302596func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002597 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2598 TpID uint32, uni string) {
2599 var gemPort uint32
2600 intfID := args[IntfID]
2601 onuID := args[OnuID]
2602 uniID := args[UniID]
2603 portNo := args[PortNo]
2604 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002605 if ipProto, ok := classifierInfo[IPProto]; ok {
2606 if ipProto.(uint32) == IPProtoDhcp {
2607 log.Info("Adding DHCP flow")
2608 if pcp, ok := classifierInfo[VlanPcp]; ok {
2609 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2610 tp_pb.Direction_UPSTREAM,
2611 pcp.(uint32))
2612 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302613 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002614 } else {
2615 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302616 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002617 }
2618
2619 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002620 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2621 if pcp, ok := classifierInfo[VlanPcp]; ok {
2622 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2623 tp_pb.Direction_UPSTREAM,
2624 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302625 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002626 } else {
2627 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302628 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002629 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002630 } else {
2631 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2632 return
2633 }
2634 } else if ethType, ok := classifierInfo[EthType]; ok {
2635 if ethType.(uint32) == EapEthType {
2636 log.Info("Adding EAPOL flow")
2637 var vlanID uint32
2638 if val, ok := classifierInfo[VlanVid]; ok {
2639 vlanID = (val.(uint32)) & VlanvIDMask
2640 } else {
2641 vlanID = DefaultMgmtVlan
2642 }
2643 if pcp, ok := classifierInfo[VlanPcp]; ok {
2644 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2645 tp_pb.Direction_UPSTREAM,
2646 pcp.(uint32))
2647
Girish Gowdrafae935c2020-02-17 19:21:44 +05302648 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002649 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302650 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002651 }
2652 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002653 } else if _, ok := actionInfo[PushVlan]; ok {
2654 log.Info("Adding upstream data rule")
2655 if pcp, ok := classifierInfo[VlanPcp]; ok {
2656 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2657 tp_pb.Direction_UPSTREAM,
2658 pcp.(uint32))
2659 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302660 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002661 } else {
2662 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302663 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002664 }
2665 } else if _, ok := actionInfo[PopVlan]; ok {
2666 log.Info("Adding Downstream data rule")
2667 if pcp, ok := classifierInfo[VlanPcp]; ok {
2668 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002669 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002670 pcp.(uint32))
2671 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302672 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002673 } else {
2674 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302675 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002676 }
2677 } else {
2678 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2679 return
2680 }
2681 // Send Techprofile download event to child device in go routine as it takes time
2682 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2683}
2684
Gamze Abakafee36392019-10-03 11:17:24 +00002685func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2686 flowIDList := f.flowsUsedByGemPort[gemPK]
2687 if len(flowIDList) > 1 {
2688 return true
2689 }
2690 return false
2691}
2692
npujarec5762e2020-01-01 14:08:48 +05302693func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2694 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002695 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2696 for _, currentGemPort := range currentGemPorts {
2697 for _, tpGemPort := range tpGemPorts {
2698 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2699 return true, currentGemPort
2700 }
2701 }
2702 }
Girish Gowdra54934262019-11-13 14:19:55 +05302703 if tpInst.InstanceCtrl.Onu == "single-instance" {
2704 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302705 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2706 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302707
2708 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2709 // still be used on other uni ports.
2710 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2711 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302712 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302713 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302714 for i := 0; i < len(tpInstances); i++ {
2715 tpI := tpInstances[i]
2716 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302717 for _, tpGemPort := range tpGemPorts {
2718 if tpGemPort.GemportID != gemPortID {
2719 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2720 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302721 }
2722 }
2723 }
2724 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302725 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002726 return false, 0
2727}
2728
salmansiddiqui7ac62132019-08-22 03:58:50 +00002729func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002730 for _, field := range flows.GetOfbFields(flow) {
2731 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002732 classifierInfo[EthType] = field.GetEthType()
2733 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002734 } else if field.Type == flows.ETH_DST {
2735 classifierInfo[EthDst] = field.GetEthDst()
2736 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002737 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002738 classifierInfo[IPProto] = field.GetIpProto()
2739 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002740 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002741 classifierInfo[InPort] = field.GetPort()
2742 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002743 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302744 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002745 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002746 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002747 classifierInfo[VlanPcp] = field.GetVlanPcp()
2748 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002749 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002750 classifierInfo[UDPDst] = field.GetUdpDst()
2751 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002752 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002753 classifierInfo[UDPSrc] = field.GetUdpSrc()
2754 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002755 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002756 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2757 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002758 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002759 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2760 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002761 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002762 classifierInfo[Metadata] = field.GetTableMetadata()
2763 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002764 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002765 classifierInfo[TunnelID] = field.GetTunnelId()
2766 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2767 } else {
2768 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2769 return
2770 }
2771 }
2772}
2773
2774func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002775 for _, action := range flows.GetActions(flow) {
2776 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002777 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002778 actionInfo[Output] = out.GetPort()
2779 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002780 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302781 return olterrors.NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002782 }
Scott Baker355d1742019-10-24 10:57:52 -07002783 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002784 actionInfo[PopVlan] = true
2785 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002786 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002787 if out := action.GetPush(); out != nil {
2788 if tpid := out.GetEthertype(); tpid != 0x8100 {
2789 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2790 } else {
2791 actionInfo[PushVlan] = true
2792 actionInfo[TPID] = tpid
2793 log.Debugw("action-type-push-vlan",
2794 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2795 }
2796 }
Scott Baker355d1742019-10-24 10:57:52 -07002797 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002798 if out := action.GetSetField(); out != nil {
2799 if field := out.GetField(); field != nil {
2800 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
Thomas Lee S94109f12020-03-03 16:39:29 +05302801 return olterrors.NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002802 }
2803 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002804 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002805 }
2806 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002807 } else if action.Type == flows.GROUP {
2808 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002809 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302810 return olterrors.NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002811 }
2812 }
2813 return nil
2814}
2815
Esin Karamanccb714b2019-11-29 15:02:06 +00002816func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2817 if ofbField := field.GetOfbField(); ofbField != nil {
2818 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2819 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2820 actionInfo[VlanVid] = vlan & 0xfff
2821 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2822 } else {
2823 log.Error("No Invalid vlan id in set vlan-vid action")
2824 }
2825 } else {
2826 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2827 }
2828 }
2829}
2830
2831func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2832 if action.GetGroup() == nil {
2833 log.Warn("No group entry found in the group action")
2834 } else {
2835 actionInfo[GroupID] = action.GetGroup().GroupId
2836 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2837 }
2838}
2839
salmansiddiqui7ac62132019-08-22 03:58:50 +00002840func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002841 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002842 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2843 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2844 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002845 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002846 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002847 log.Debugw("upstream pon-to-controller-flow,inport-in-tunnelid", log.Fields{"newInPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002848 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302849 return olterrors.NewErrNotFound("child-in-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002850 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2851 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002852 }
2853 }
2854 } else {
2855 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2856 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002857 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002858 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002859 actionInfo[Output] = uniPort
2860 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 +00002861 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302862 return olterrors.NewErrNotFound("out-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002863 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2864 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002865 }
2866 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2867 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002868 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002869 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002870 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2871 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002872 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302873 return olterrors.NewErrNotFound("nni-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002874 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2875 "in-port": classifierInfo[InPort].(uint32),
2876 "out-port": actionInfo[Output].(uint32),
2877 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002878 }
2879 }
2880 }
2881 return nil
2882}
Gamze Abakafee36392019-10-03 11:17:24 +00002883
Chaitrashree G S90a17952019-11-14 21:51:21 -05002884func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002885 /* Metadata 8 bytes:
2886 Most Significant 2 Bytes = Inner VLAN
2887 Next 2 Bytes = Tech Profile ID(TPID)
2888 Least Significant 4 Bytes = Port ID
2889 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2890 subscriber related flows.
2891 */
2892 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2893 if metadata == 0 {
Thomas Lee S94109f12020-03-03 16:39:29 +05302894 return 0, olterrors.NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002895 }
2896 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002897 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002898}
2899
2900func appendUnique(slice []uint32, item uint32) []uint32 {
2901 for _, sliceElement := range slice {
2902 if sliceElement == item {
2903 return slice
2904 }
2905 }
2906 return append(slice, item)
2907}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302908
2909// getNniIntfID gets nni intf id from the flow classifier/action
2910func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2911
2912 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2913 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002914 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2915 if err != nil {
2916 log.Debugw("invalid-action-port-number",
2917 log.Fields{
2918 "port-number": action[Output].(uint32),
2919 "error": err})
2920 return uint32(0), err
2921 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302922 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2923 return intfID, nil
2924 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002925 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2926 if err != nil {
2927 log.Debugw("invalid-classifier-port-number",
2928 log.Fields{
2929 "port-number": action[Output].(uint32),
2930 "error": err})
2931 return uint32(0), err
2932 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302933 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2934 return intfID, nil
2935 }
2936 return uint32(0), nil
2937}
2938
2939// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302940func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302941 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2942
2943 f.lockCache.Lock()
2944 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002945 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302946 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002947 if lookupGemPort == gemPort {
2948 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2949 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2950 return
2951 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302952 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002953 f.packetInGemPort[pktInkey] = gemPort
2954
npujarec5762e2020-01-01 14:08:48 +05302955 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002956 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 +05302957 return
2958}
2959
2960// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302961func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302962
2963 f.lockCache.Lock()
2964 defer f.lockCache.Unlock()
2965 onugem := f.onuGemInfo[intfID]
2966 for idx, onu := range onugem {
2967 if onu.OnuID == onuID {
2968 for _, uni := range onu.UniPorts {
2969 if uni == portNum {
2970 log.Debugw("uni already in cache, no need to update cache and kv store",
2971 log.Fields{"uni": portNum})
2972 return
2973 }
2974 }
2975 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2976 f.onuGemInfo[intfID] = onugem
2977 }
2978 }
npujarec5762e2020-01-01 14:08:48 +05302979 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302980}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302981
npujarec5762e2020-01-01 14:08:48 +05302982func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2983 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302984 if err != nil {
2985 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2986 return
2987 }
2988 for gem, FlowIDs := range flowIDsList {
2989 gemPK := gemPortKey{intf, uint32(gem)}
2990 f.flowsUsedByGemPort[gemPK] = FlowIDs
2991 }
2992 return
2993}
Esin Karamanccb714b2019-11-29 15:02:06 +00002994
2995//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2996//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302997func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2998 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002999 if err != nil {
3000 log.Error("Failed to get pon interface to multicast queue map")
3001 return
3002 }
3003 for intf, queueInfo := range storedMulticastQueueMap {
3004 q := queueInfoBrief{
3005 gemPortID: queueInfo[0],
3006 servicePriority: queueInfo[1],
3007 }
3008 f.interfaceToMcastQueueMap[intf] = &q
3009 }
3010}
3011
3012//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
3013//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
3014//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05303015func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
3016 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00003017 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05303018 return nil, false, olterrors.NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00003019 }
3020 if exists {
3021 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3022 }
3023 return nil, exists, nil
3024}
3025
3026func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3027 groupDesc := ofp.OfpGroupDesc{
3028 Type: ofp.OfpGroupType_OFPGT_ALL,
3029 GroupId: groupID,
3030 }
3031 groupEntry := ofp.OfpGroupEntry{
3032 Desc: &groupDesc,
3033 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003034 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003035 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003036 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003037 bucket := ofp.OfpBucket{
3038 Actions: acts,
3039 }
3040 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003041 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003042 return &groupEntry
3043}