blob: b79e4bd32938fcbcc34ce5cc742ad118bbaaea82 [file] [log] [blame]
manikkaraj kbf256be2019-03-25 00:13:48 +05301/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070017//Package adaptercore provides the utility for olt devices, flows and statistics
manikkaraj kbf256be2019-03-25 00:13:48 +053018package adaptercore
19
20import (
21 "context"
22 "crypto/md5"
Matteo Scandolo6056e822019-11-13 14:05:29 -080023 "encoding/hex"
manikkaraj kbf256be2019-03-25 00:13:48 +053024 "encoding/json"
manikkaraj kbf256be2019-03-25 00:13:48 +053025 "fmt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040026 "math/big"
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"
Manikkaraj k884c1242019-04-11 16:26:42 +053034 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
Esin Karamanccb714b2019-11-29 15:02:06 +000035 "github.com/opencord/voltha-protos/v3/go/common"
36 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
37 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
38 openoltpb2 "github.com/opencord/voltha-protos/v3/go/openolt"
39 tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
40 "github.com/opencord/voltha-protos/v3/go/voltha"
Chaitrashree G S579fe732019-08-20 20:50:47 -040041
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040042 //deepcopy "github.com/getlantern/deepcopy"
Girish Gowdra3d633032019-12-10 16:37:05 +053043 "github.com/EagleChen/mapmutex"
Daniele Rossi22db98e2019-07-11 11:50:00 +000044 "google.golang.org/grpc/codes"
45 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053046)
47
48const (
49 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053050
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070051 //HsiaFlow flow category
52 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053053
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070054 //EapolFlow flow category
55 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053056
Manikkaraj kb1d51442019-07-23 10:41:02 -040057 //DhcpFlow flow category
58 DhcpFlow = "DHCP_FLOW"
59
Esin Karamanccb714b2019-11-29 15:02:06 +000060 //MulticastFlow flow category
61 MulticastFlow = "MULTICAST_FLOW"
62
Esin Karamanae41e2b2019-12-17 18:13:13 +000063 //IgmpFlow flow category
64 IgmpFlow = "IGMP_FLOW"
65
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070066 //IPProtoDhcp flow category
67 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053068
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070069 //IPProtoIgmp flow category
70 IPProtoIgmp = 2
71
72 //EapEthType eapethtype value
73 EapEthType = 0x888e
74 //LldpEthType lldp ethtype value
75 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000076 //IPv4EthType IPv4 ethernet type value
77 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070078
79 //IgmpProto proto value
80 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053081
82 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070083
Humera Kouser94d7a842019-08-25 19:04:32 -040084 //ReservedVlan Transparent Vlan
David K. Bainbridge82efc492019-09-04 09:57:11 -070085 ReservedVlan = 4095
Harsh Awasthiea45af72019-08-26 02:39:00 -040086
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070087 //DefaultMgmtVlan default vlan value
88 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053089
manikkaraj kbf256be2019-03-25 00:13:48 +053090 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070091
David K. Bainbridge82efc492019-09-04 09:57:11 -070092 //Upstream constant
93 Upstream = "upstream"
94 //Downstream constant
95 Downstream = "downstream"
Esin Karamanccb714b2019-11-29 15:02:06 +000096 //Multicast constant
97 Multicast = "multicast"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070098 //PacketTagType constant
99 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700100 //Untagged constant
101 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700102 //SingleTag constant
103 SingleTag = "single_tag"
104 //DoubleTag constant
105 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530106
107 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700108
109 //EthType constant
110 EthType = "eth_type"
Esin Karamanccb714b2019-11-29 15:02:06 +0000111 //EthDst constant
112 EthDst = "eth_dst"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700113 //TPID constant
114 TPID = "tpid"
115 //IPProto constant
116 IPProto = "ip_proto"
117 //InPort constant
118 InPort = "in_port"
119 //VlanVid constant
120 VlanVid = "vlan_vid"
121 //VlanPcp constant
122 VlanPcp = "vlan_pcp"
123
124 //UDPDst constant
125 UDPDst = "udp_dst"
126 //UDPSrc constant
127 UDPSrc = "udp_src"
128 //Ipv4Dst constant
129 Ipv4Dst = "ipv4_dst"
130 //Ipv4Src constant
131 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700132 //Metadata constant
133 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700134 //TunnelID constant
135 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700136 //Output constant
137 Output = "output"
Esin Karamanccb714b2019-11-29 15:02:06 +0000138 //GroupID constant
139 GroupID = "group_id"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700140 // Actions
141
142 //PopVlan constant
143 PopVlan = "pop_vlan"
144 //PushVlan constant
145 PushVlan = "push_vlan"
146 //TrapToHost constant
147 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400148 //MaxMeterBand constant
149 MaxMeterBand = 2
150 //VlanPCPMask contant
151 VlanPCPMask = 0xFF
152 //VlanvIDMask constant
153 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000154 //IntfID constant
155 IntfID = "intfId"
156 //OnuID constant
157 OnuID = "onuId"
158 //UniID constant
159 UniID = "uniId"
160 //PortNo constant
161 PortNo = "portNo"
162 //AllocID constant
163 AllocID = "allocId"
Esin Karamanccb714b2019-11-29 15:02:06 +0000164
165 //NoneOnuID constant
166 NoneOnuID = -1
167 //NoneUniID constant
168 NoneUniID = -1
169 //NoneGemPortID constant
170 NoneGemPortID = -1
Girish Gowdrafae935c2020-02-17 19:21:44 +0530171
172 // BinaryStringPrefix is binary string prefix
173 BinaryStringPrefix = "0b"
174 // BinaryBit1 is binary bit 1 expressed as a character
175 BinaryBit1 = '1'
manikkaraj kbf256be2019-03-25 00:13:48 +0530176)
177
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400178type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700179 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400180 gemPort uint32
181}
182
Girish Gowdra3d633032019-12-10 16:37:05 +0530183type pendingFlowDeleteKey struct {
184 intfID uint32
185 onuID uint32
186 uniID uint32
187}
188
189type tpLockKey struct {
190 intfID uint32
191 onuID uint32
192 uniID uint32
193}
194
Gamze Abakafee36392019-10-03 11:17:24 +0000195type schedQueue struct {
196 direction tp_pb.Direction
197 intfID uint32
198 onuID uint32
199 uniID uint32
200 tpID uint32
201 uniPort uint32
202 tpInst *tp.TechProfile
203 meterID uint32
204 flowMetadata *voltha.FlowMetadata
205}
206
Esin Karamanccb714b2019-11-29 15:02:06 +0000207type queueInfoBrief struct {
208 gemPortID uint32
209 servicePriority uint32
210}
211
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700212//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530213type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000214 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000215 deviceHandler *DeviceHandler
216 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000217 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530218 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
219 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
220 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
221 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530222 pendingFlowDelete sync.Map
223 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
Esin Karamanccb714b2019-11-29 15:02:06 +0000224 perUserFlowHandleLock *mapmutex.Mutex
225 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 +0530226}
227
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700228//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
npujarec5762e2020-01-01 14:08:48 +0530229func NewFlowManager(ctx context.Context, dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530230 log.Info("Initializing flow manager")
231 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530232 var err error
233 var idx uint32
234
manikkaraj kbf256be2019-03-25 00:13:48 +0530235 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530236 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000237 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530238 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530239 log.Error("Error while populating tech profile mgr\n")
240 return nil
241 }
William Kurkian740a09c2019-10-23 17:07:38 -0400242 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530243 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
244 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
245 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
246 ponPorts := rMgr.DevInfo.GetPonPorts()
247 //Load the onugem info cache from kv store on flowmanager start
248 for idx = 0; idx < ponPorts; idx++ {
npujarec5762e2020-01-01 14:08:48 +0530249 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(ctx, idx); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530250 log.Error("Failed to load onu gem info cache")
251 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530252 //Load flowID list per gem map per interface from the kvstore.
npujarec5762e2020-01-01 14:08:48 +0530253 flowMgr.loadFlowIDlistForGem(ctx, idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530254 }
255 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530256 flowMgr.pendingFlowDelete = sync.Map{}
257 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
Esin Karamanccb714b2019-11-29 15:02:06 +0000258 flowMgr.interfaceToMcastQueueMap = make(map[uint32]*queueInfoBrief)
259 //load interface to multicast queue map from kv store
npujarec5762e2020-01-01 14:08:48 +0530260 flowMgr.loadInterfaceToMulticastQueueMap(ctx)
manikkaraj kbf256be2019-03-25 00:13:48 +0530261 log.Info("Initialization of flow manager success!!")
262 return &flowMgr
263}
264
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700265func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700266 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400267 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700268 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700269 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400270 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700271 return uint64(flowID), nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000272 } else if direction == Multicast {
273 log.Debug("multicast flow, shifting id")
274 return 0x2<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400275 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800276 return 0, NewErrInvalidValue(log.Fields{"direction": direction}, nil).Log()
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400277 }
278}
279
npujarec5762e2020-01-01 14:08:48 +0530280func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400281 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700282 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000283 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
284 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
285 if !ok {
286 flowIDList = []uint32{deviceFlow.FlowId}
287 }
288 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
289 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530290 // update the flowids for a gem to the KVstore
npujarec5762e2020-01-01 14:08:48 +0530291 f.resourceMgr.UpdateFlowIDsForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400292}
293
npujarec5762e2020-01-01 14:08:48 +0530294func (f *OpenOltFlowMgr) divideAndAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000295 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
296 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000297 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530298 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400299 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530300
Manikkaraj kb1d51442019-07-23 10:41:02 -0400301 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000302 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400303 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
304 // is because the flow is an NNI flow and there would be no onu resources associated with it
305 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400306 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400307 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530308 return
309 }
310
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530311 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400312 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530313
314 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
315 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
npujarec5762e2020-01-01 14:08:48 +0530316 allocID, gemPorts, TpInst = f.createTcontGemports(ctx, intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +0530317 if allocID == 0 || gemPorts == nil || TpInst == nil {
318 log.Error("alloc-id-gem-ports-tp-unavailable")
319 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
320 return
321 }
322 args := make(map[string]uint32)
323 args[IntfID] = intfID
324 args[OnuID] = onuID
325 args[UniID] = uniID
326 args[PortNo] = portNo
327 args[AllocID] = allocID
328
329 /* Flows can be added specific to gemport if p-bits are received.
330 * If no pbit mentioned then adding flows for all gemports
331 */
npujarec5762e2020-01-01 14:08:48 +0530332 f.checkAndAddFlow(ctx, args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
Girish Gowdra3d633032019-12-10 16:37:05 +0530333 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
334 } else {
335 log.Errorw("failed to acquire per user flow handle lock",
336 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400337 return
338 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530339}
340
salmansiddiqui7ac62132019-08-22 03:58:50 +0000341// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530342func (f *OpenOltFlowMgr) CreateSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400343
Gamze Abakafee36392019-10-03 11:17:24 +0000344 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
345 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
346 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400347
Gamze Abakafee36392019-10-03 11:17:24 +0000348 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000349 if err != nil {
350 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400351 }
352
353 /* Lets make a simple assumption that if the meter-id is present on the KV store,
354 * then the scheduler and queues configuration is applied on the OLT device
355 * in the given direction.
356 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000357
Manikkaraj kb1d51442019-07-23 10:41:02 -0400358 var SchedCfg *tp_pb.SchedulerConfig
npujarec5762e2020-01-01 14:08:48 +0530359 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400360 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000361 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 -0400362 return err
363 }
364 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000365 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400366 log.Debug("Scheduler already created for upstream")
367 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400368 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800369 return NewErrInvalidValue(log.Fields{
370 "unsupported": "meter-id",
371 "kv-store-meter-id": KvStoreMeter.MeterId,
372 "meter-id-in-flow": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400373 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000374
Gamze Abakafee36392019-10-03 11:17:24 +0000375 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000376
Gamze Abakafee36392019-10-03 11:17:24 +0000377 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000378 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000379 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000380 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400381 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000382
383 if err != nil {
384 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
385 return err
386 }
387
Manikkaraj kb1d51442019-07-23 10:41:02 -0400388 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000389 if sq.flowMetadata != nil {
390 for _, meter := range sq.flowMetadata.Meters {
391 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400392 meterConfig = meter
393 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
394 break
395 }
396 }
397 } else {
398 log.Error("Flow-metadata-is-not-present-in-flow")
399 }
400 if meterConfig == nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800401 return NewErrNotFound("meterbands", log.Fields{
402 "reason": "Could-not-get-meterbands-from-flowMetadata",
403 "flow-metadata": sq.flowMetadata,
404 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400405 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000406 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800407 return NewErrInvalidValue(log.Fields{
408 "reason": "Invalid-number-of-bands-in-meter",
409 "meterband-count": len(meterConfig.Bands),
410 "metabands": meterConfig.Bands,
411 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400412 }
413 cir := meterConfig.Bands[0].Rate
414 cbs := meterConfig.Bands[0].BurstSize
415 eir := meterConfig.Bands[1].Rate
416 ebs := meterConfig.Bands[1].BurstSize
417 pir := cir + eir
418 pbs := cbs + ebs
419 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
420
Gamze Abakafee36392019-10-03 11:17:24 +0000421 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400422
npujarec5762e2020-01-01 14:08:48 +0530423 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000424 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 -0400425 return err
426 }
427
salmansiddiqui7ac62132019-08-22 03:58:50 +0000428 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400429 * store the meter id on the KV store, for further reference.
430 */
npujarec5762e2020-01-01 14:08:48 +0530431 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 +0000432 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400433 return err
434 }
435 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
436 "Meter": meterConfig})
437 return nil
438}
439
npujarec5762e2020-01-01 14:08:48 +0530440func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000441
442 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
443
444 if err != nil {
445 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
446 return err
447 }
448
449 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530450 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000451 IntfId: sq.intfID, OnuId: sq.onuID,
452 UniId: sq.uniID, PortNo: sq.uniPort,
453 TrafficScheds: TrafficSched}); err != nil {
454 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
455 return err
456 }
457
458 // On receiving the CreateTrafficQueues request, the driver should create corresponding
459 // downstream queues.
460 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530461 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000462 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
463 UniId: sq.uniID, PortNo: sq.uniPort,
464 TrafficQueues: trafficQueues}); err != nil {
465 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
466 return err
467 }
468
Esin Karamanccb714b2019-11-29 15:02:06 +0000469 if sq.direction == tp_pb.Direction_DOWNSTREAM {
470 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
471 if len(multicastTrafficQueues) > 0 {
472 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
473 //assumed that there is only one queue per PON for the multicast service
474 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
475 //just put it in interfaceToMcastQueueMap to use for building group members
476 multicastQueuePerPonPort := multicastTrafficQueues[0]
477 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
478 gemPortID: multicastQueuePerPonPort.GemportId,
479 servicePriority: multicastQueuePerPonPort.Priority,
480 }
481 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530482 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000483 multicastQueuePerPonPort.GemportId,
484 multicastQueuePerPonPort.Priority)
485 }
486 }
487 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000488 return nil
489}
490
salmansiddiqui7ac62132019-08-22 03:58:50 +0000491// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530492func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400493
494 var Direction string
495 var SchedCfg *tp_pb.SchedulerConfig
496 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000497 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
498 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
499 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000500 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400501 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000502 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000503 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400504 Direction = "downstream"
505 }
506
Girish Kumar8f73fe02019-12-09 13:19:37 +0000507 if err != nil {
508 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
509 return err
510 }
511
npujarec5762e2020-01-01 14:08:48 +0530512 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400513 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000514 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400515 return err
516 }
517 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000518 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 -0400519 return nil
520 }
521 cir := KVStoreMeter.Bands[0].Rate
522 cbs := KVStoreMeter.Bands[0].BurstSize
523 eir := KVStoreMeter.Bands[1].Rate
524 ebs := KVStoreMeter.Bands[1].BurstSize
525 pir := cir + eir
526 pbs := cbs + ebs
527
528 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
529
Gamze Abakafee36392019-10-03 11:17:24 +0000530 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000531
532 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
533 if err != nil {
534 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
535 return err
536 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400537
npujarec5762e2020-01-01 14:08:48 +0530538 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000539 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
540 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400541 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000542 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400543 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400544 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000545 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530546 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000547 IntfId: sq.intfID, OnuId: sq.onuID,
548 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400549 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000550 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400551 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400552 }
553
salmansiddiqui7ac62132019-08-22 03:58:50 +0000554 log.Debug("Removed traffic schedulers successfully")
555
556 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400557 * delete the meter id on the KV store.
558 */
npujarec5762e2020-01-01 14:08:48 +0530559 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400560 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000561 log.Errorf("Failed to remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000562 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400563 }
564 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
565 return err
566}
567
Gamze Abakafee36392019-10-03 11:17:24 +0000568// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530569func (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 +0000570 var allocIDs []uint32
571 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530572 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530573 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000574 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000575
npujarec5762e2020-01-01 14:08:48 +0530576 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
577 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400578
579 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530580
581 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
582
Manikkaraj kb1d51442019-07-23 10:41:02 -0400583 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530584 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000585 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530586 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530587 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000588 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530589 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000590 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000591 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530592 }
npujarec5762e2020-01-01 14:08:48 +0530593 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530594 } else {
595 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530596 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530597 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400598 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000599 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
600 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530601 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400602 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000603 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400604 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530605 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400606 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000607 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
608 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530609 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400610 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000611 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400612 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530613 }
Gamze Abakafee36392019-10-03 11:17:24 +0000614
615 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000616 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000617 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400618 }
Gamze Abakafee36392019-10-03 11:17:24 +0000619
Girish Gowdra3d633032019-12-10 16:37:05 +0530620 if tpInstanceExists {
621 return allocID, gemPortIDs, techProfileInstance
622 }
623
624 allocIDs = appendUnique(allocIDs, allocID)
625 for _, gemPortID := range gemPortIDs {
626 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
627 }
628
Gamze Abakafee36392019-10-03 11:17:24 +0000629 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530630 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530631 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000632 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530633}
634
npujarec5762e2020-01-01 14:08:48 +0530635func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530636
637 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700638 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530639 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530640 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530641 log.Error("Errow while uploading allocID to KV store")
642 }
npujarec5762e2020-01-01 14:08:48 +0530643 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530644 log.Error("Errow while uploading GEMports to KV store")
645 }
npujarec5762e2020-01-01 14:08:48 +0530646 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530647 log.Error("Errow while uploading gemtopon map to KV store")
648 }
649 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400650 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530651 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400652 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530653}
654
655func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000656 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530657 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000658 for _, intfID := range techRange.IntfIds {
659 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400660 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000661 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530662 }
663 }
664 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400665 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800666 return NewErrInvalidValue(log.Fields{
667 "reason": "TP count does not match number of PON ports",
668 "tech-profile-count": tpCount,
669 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530670 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400671 log.Infow("Populated techprofile for ponports successfully",
672 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530673 return nil
674}
675
npujarec5762e2020-01-01 14:08:48 +0530676func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530677 portNo uint32, uplinkClassifier map[string]interface{},
678 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800679 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700680 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530681 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800682 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700683 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530684 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530685}
686
npujarec5762e2020-01-01 14:08:48 +0530687func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530688 portNo uint32, downlinkClassifier map[string]interface{},
689 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800690 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700691 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530692 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
693 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400694 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
695 if vlan, exists := downlinkClassifier[VlanVid]; exists {
696 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700697 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400698 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
699 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800700 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400701 }
702 }
703 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530704 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400705
Manikkaraj k884c1242019-04-11 16:26:42 +0530706 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700707 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400708 // vlan_vid is a uint32. must be type asserted as such or conversion fails
709 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530710 if ok {
711 downlinkAction[VlanVid] = dlClVid & 0xfff
712 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800713 return NewErrInvalidValue(log.Fields{
714 "reason": "failed to convert VLANID classifier",
715 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530716 }
717
David K. Bainbridge794735f2020-02-11 21:01:37 -0800718 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700719 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530720}
721
npujarec5762e2020-01-01 14:08:48 +0530722func (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 +0530723 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800724 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530725 /* One of the OLT platform (Broadcom BAL) requires that symmetric
726 flows require the same flow_id to be used across UL and DL.
727 Since HSIA flow is the only symmetric flow currently, we need to
728 re-use the flow_id across both direction. The 'flow_category'
729 takes priority over flow_cookie to find any available HSIA_FLOW
730 id for the ONU.
731 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700732 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
733 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530734 "logicalFlow": *logicalFlow})
Girish Gowdrafae935c2020-02-17 19:21:44 +0530735 var vlanPbit uint32 = 0xff // means no pbit
Manikkaraj kb1d51442019-07-23 10:41:02 -0400736 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000737 vlanPbit = classifier[VlanPcp].(uint32)
738 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800739 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +0530740 log.Debugw("pbit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400741 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700742 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530743 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800744 log.Debug("flow-already-exists")
745 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530746 }
npujarec5762e2020-01-01 14:08:48 +0530747 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530748 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800749 return NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530750 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800751 classifierProto, err := makeOpenOltClassifierField(classifier)
752 if err != nil {
753 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530754 }
755 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800756 actionProto, err := makeOpenOltActionField(action)
757 if err != nil {
758 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530759 }
760 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800761 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530762 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800763 return NewErrNotFound("nni-interface-id",
764 log.Fields{
765 "classifier": classifier,
766 "action": action,
767 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530768 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700769 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
770 OnuId: int32(onuID),
771 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000772 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530773 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700774 AllocId: int32(allocID),
775 NetworkIntfId: int32(networkIntfID),
776 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530777 Classifier: classifierProto,
778 Action: actionProto,
779 Priority: int32(logicalFlow.Priority),
780 Cookie: logicalFlow.Cookie,
781 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800782 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
783 return NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530784 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800785 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
786 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
787 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
788 flow.OnuId,
789 flow.UniId,
790 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
791 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
792 }
793 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530794}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000795
David K. Bainbridge794735f2020-02-11 21:01:37 -0800796func (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 +0530797
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530798 networkIntfID, err := getNniIntfID(classifier, action)
799 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800800 return NewErrNotFound("nni-interface-id", log.Fields{
801 "classifier": classifier,
802 "action": action},
803 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530804 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530805
806 // Clear the action map
807 for k := range action {
808 delete(action, k)
809 }
810
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700811 action[TrapToHost] = true
812 classifier[UDPSrc] = uint32(68)
813 classifier[UDPDst] = uint32(67)
814 classifier[PacketTagType] = SingleTag
815 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530816
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700817 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530818 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530819 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800820 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530821 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530822
David K. Bainbridge794735f2020-02-11 21:01:37 -0800823 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 +0530824
825 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800826 return NewErrNotFound("flow", log.Fields{
827 "interface-id": intfID,
828 "gem-port": gemPortID,
829 "cookie": flowStoreCookie},
830 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530831 }
832
833 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
834
David K. Bainbridge794735f2020-02-11 21:01:37 -0800835 classifierProto, err := makeOpenOltClassifierField(classifier)
836 if err != nil {
837 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530838 }
839 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800840 actionProto, err := makeOpenOltActionField(action)
841 if err != nil {
842 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530843 }
844
David K. Bainbridge794735f2020-02-11 21:01:37 -0800845 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700846 OnuId: int32(onuID),
847 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530848 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700849 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700850 AllocId: int32(allocID),
851 NetworkIntfId: int32(networkIntfID),
852 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530853 Classifier: classifierProto,
854 Action: actionProto,
855 Priority: int32(logicalFlow.Priority),
856 Cookie: logicalFlow.Cookie,
857 PortNo: portNo}
858
David K. Bainbridge794735f2020-02-11 21:01:37 -0800859 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
860 return NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
861 }
862 log.Debug("DHCP UL flow added to device successfully")
863 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
864 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
865 dhcpFlow.OnuId,
866 dhcpFlow.UniId,
867 dhcpFlow.FlowId, flowsToKVStore); err != nil {
868 return NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530869 }
870
David K. Bainbridge794735f2020-02-11 21:01:37 -0800871 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530872}
873
Esin Karamanae41e2b2019-12-17 18:13:13 +0000874//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530875func (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 -0800876 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
877 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000878}
879
880//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530881func (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 -0800882 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000883
884 networkIntfID, err := getNniIntfID(classifier, action)
885 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800886 return NewErrNotFound("nni-interface-id", log.Fields{
887 "classifier": classifier,
888 "action": action},
889 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000890 }
891
892 // Clear the action map
893 for k := range action {
894 delete(action, k)
895 }
896
897 action[TrapToHost] = true
898 classifier[PacketTagType] = SingleTag
899 delete(classifier, VlanVid)
900
901 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530902 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800903 log.Debug("Flow-exists-not-re-adding")
904 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000905 }
906
npujarec5762e2020-01-01 14:08:48 +0530907 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 +0000908
909 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800910 return NewErrNotFound("flow-id", log.Fields{
911 "interface-id": intfID,
912 "oni-id": onuID,
913 "cookie": flowStoreCookie,
914 "flow-type": flowType},
915 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000916 }
917
918 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
919
David K. Bainbridge794735f2020-02-11 21:01:37 -0800920 classifierProto, err := makeOpenOltClassifierField(classifier)
921 if err != nil {
922 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000923 }
924 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800925 actionProto, err := makeOpenOltActionField(action)
926 if err != nil {
927 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000928 }
929
David K. Bainbridge794735f2020-02-11 21:01:37 -0800930 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000931 OnuId: int32(onuID),
932 UniId: int32(uniID),
933 FlowId: flowID,
934 FlowType: Upstream,
935 AllocId: int32(allocID),
936 NetworkIntfId: int32(networkIntfID),
937 GemportId: int32(gemPortID),
938 Classifier: classifierProto,
939 Action: actionProto,
940 Priority: int32(logicalFlow.Priority),
941 Cookie: logicalFlow.Cookie,
942 PortNo: portNo}
943
David K. Bainbridge794735f2020-02-11 21:01:37 -0800944 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
945 return NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
946 }
947 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000948
David K. Bainbridge794735f2020-02-11 21:01:37 -0800949 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
950 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
951 flow.OnuId,
952 flow.UniId,
953 flow.FlowId, flowsToKVStore); err != nil {
954 return NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000955 }
956
David K. Bainbridge794735f2020-02-11 21:01:37 -0800957 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000958}
959
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700960// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Girish Gowdrafae935c2020-02-17 19:21:44 +0530961func (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 -0700962 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 +0530963
964 uplinkClassifier := make(map[string]interface{})
965 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530966
manikkaraj kbf256be2019-03-25 00:13:48 +0530967 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700968 uplinkClassifier[EthType] = uint32(EapEthType)
969 uplinkClassifier[PacketTagType] = SingleTag
970 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530971 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700972 uplinkAction[TrapToHost] = true
973 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530974 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800975 log.Debug("Flow-exists-not-re-adding")
976 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530977 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530978 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530979 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530980 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800981 return NewErrNotFound("flow-id", log.Fields{
982 "interface-id": intfID,
983 "onu-id": onuID,
984 "coookie": flowStoreCookie},
985 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530986 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700987 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530988
David K. Bainbridge794735f2020-02-11 21:01:37 -0800989 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
990 if err != nil {
991 return NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530992 }
993 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800994 actionProto, err := makeOpenOltActionField(uplinkAction)
995 if err != nil {
996 return NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530997 }
998 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800999 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301000 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001001 return NewErrNotFound("nni-interface-id", log.Fields{
1002 "classifier": classifier,
1003 "action": action},
1004 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301005 }
1006
David K. Bainbridge794735f2020-02-11 21:01:37 -08001007 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001008 OnuId: int32(onuID),
1009 UniId: int32(uniID),
1010 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001011 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001012 AllocId: int32(allocID),
1013 NetworkIntfId: int32(networkIntfID),
1014 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301015 Classifier: classifierProto,
1016 Action: actionProto,
1017 Priority: int32(logicalFlow.Priority),
1018 Cookie: logicalFlow.Cookie,
1019 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001020 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
1021 return NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
1022 }
1023 log.Debug("EAPOL UL flow added to device successfully")
1024 flowCategory := "EAPOL"
1025 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1026 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1027 upstreamFlow.OnuId,
1028 upstreamFlow.UniId,
1029 upstreamFlow.FlowId,
1030 /* lowCategory, */
1031 flowsToKVStore); err != nil {
1032 return NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301033 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301034
manikkaraj kbf256be2019-03-25 00:13:48 +05301035 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001036 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301037}
1038
David K. Bainbridge794735f2020-02-11 21:01:37 -08001039func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001040 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001041
1042 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1043 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1044 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
1045 vid := vlanID & VlanvIDMask
1046 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001047 classifier.OVid = vid
1048 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301049 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001050 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1051 vid := uint32(metadata)
1052 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001053 classifier.IVid = vid
1054 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301055 }
Girish Gowdrafae935c2020-02-17 19:21:44 +05301056 // Use VlanPCPMask (0xff) to signify NO PCP. Else use valid PCP (0 to 7)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001057 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Girish Gowdrafae935c2020-02-17 19:21:44 +05301058 classifier.OPbits = vlanPcp
1059 } else {
1060 classifier.OPbits = VlanPCPMask
manikkaraj kbf256be2019-03-25 00:13:48 +05301061 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001062 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1063 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1064 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1065 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001066 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001067 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1068 classifier.PktTagType = pktTagType
1069
1070 switch pktTagType {
1071 case SingleTag:
1072 case DoubleTag:
1073 case Untagged:
1074 default:
David K. Bainbridge794735f2020-02-11 21:01:37 -08001075 return nil, NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301076 }
1077 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001078 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301079}
1080
David K. Bainbridge794735f2020-02-11 21:01:37 -08001081func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001082 var actionCmd openoltpb2.ActionCmd
1083 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301084 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001085 if _, ok := actionInfo[PopVlan]; ok {
1086 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301087 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001088 } else if _, ok := actionInfo[PushVlan]; ok {
1089 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301090 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001091 } else if _, ok := actionInfo[TrapToHost]; ok {
1092 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301093 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001094 return nil, NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301095 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001096 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301097}
1098
Manikkaraj kb1d51442019-07-23 10:41:02 -04001099func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1100 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301101}
1102
Gamze Abakafee36392019-10-03 11:17:24 +00001103// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301104func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1105 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001106 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001107 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301108 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +00001109 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 +05301110 // return err
1111 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001112 }
1113 }
1114 return nil
1115}
1116
1117// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301118func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001119 if uniPortName == "" {
1120 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1121 }
npujarec5762e2020-01-01 14:08:48 +05301122 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001123 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1124 return err
1125 }
1126 return nil
1127}
1128
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001129func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301130 if len(classifier) == 0 { // should never happen
1131 log.Error("Invalid classfier object")
1132 return 0
1133 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301134 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301135 var jsonData []byte
1136 var flowString string
1137 var err error
1138 // TODO: Do we need to marshall ??
1139 if jsonData, err = json.Marshal(classifier); err != nil {
1140 log.Error("Failed to encode classifier")
1141 return 0
1142 }
1143 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001144 if gemPortID != 0 {
1145 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301146 }
1147 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001148 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301149 hash := big.NewInt(0)
1150 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301151 generatedHash := hash.Uint64()
1152 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1153 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301154}
1155
npujarec5762e2020-01-01 14:08:48 +05301156func (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 +05301157 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001158 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001159 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1160 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1161 */
1162 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001163 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001164 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001165 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001166 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001167 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301168 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001169 if existingFlows != nil {
1170 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001171 //for _, f := range *existingFlows {
1172 // flows = append(flows, f)
1173 //}
1174 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001175 }
1176 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 +05301177 return &flows
1178}
1179
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001180//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1181// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1182// var intfId uint32
1183// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1184// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1185// */
1186// if flow.AccessIntfId != -1 {
1187// intfId = uint32(flow.AccessIntfId)
1188// } else {
1189// intfId = uint32(flow.NetworkIntfId)
1190// }
1191// // Get existing flows matching flowid for given subscriber from KV store
1192// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1193// if existingFlows != nil {
1194// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1195// for _, f := range *existingFlows {
1196// flows = append(flows, f)
1197// }
1198// }
1199// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1200// return &flows
1201//}
1202
npujarec5762e2020-01-01 14:08:48 +05301203func (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 -04001204 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301205 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001206 log.Debug("Error while Storing flow into KV store")
1207 return err
1208 }
1209 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301210 return nil
1211}
1212
David K. Bainbridge794735f2020-02-11 21:01:37 -08001213func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001214
1215 var intfID uint32
1216 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1217 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1218 */
1219 if deviceFlow.AccessIntfId != -1 {
1220 intfID = uint32(deviceFlow.AccessIntfId)
1221 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001222 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001223 intfID = uint32(deviceFlow.NetworkIntfId)
1224 }
1225
manikkaraj kbf256be2019-03-25 00:13:48 +05301226 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1227 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001228
1229 st, _ := status.FromError(err)
1230 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001231 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001232 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301233 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001234
1235 if err != nil {
1236 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301237 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001238 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001239 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301240 if deviceFlow.GemportId != -1 {
1241 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301242 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301243 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301244 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001245 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001246}
1247
David K. Bainbridge794735f2020-02-11 21:01:37 -08001248func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001249 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1250 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1251 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001252 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1253 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1254 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001255 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001256 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001257 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001258 return err
serkant.uluderya245caba2019-09-24 23:15:29 -07001259
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001260 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001261 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001262 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301263}
1264
1265/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1266 //update core flows_proxy : flows_proxy.update('/', flows)
1267}
1268
1269func generateStoredId(flowId uint32, direction string)uint32{
1270
David K. Bainbridge82efc492019-09-04 09:57:11 -07001271 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301272 log.Debug("Upstream flow shifting flowid")
1273 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001274 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301275 log.Debug("Downstream flow not shifting flowid")
1276 return flowId
1277 }else{
1278 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1279 return flowId
1280 }
1281}
1282
1283*/
1284
David K. Bainbridge794735f2020-02-11 21:01:37 -08001285func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001286
1287 classifierInfo := make(map[string]interface{})
1288 actionInfo := make(map[string]interface{})
1289
1290 classifierInfo[EthType] = uint32(LldpEthType)
1291 classifierInfo[PacketTagType] = Untagged
1292 actionInfo[TrapToHost] = true
1293
1294 // LLDP flow is installed to trap LLDP packets on the NNI port.
1295 // We manage flow_id resource pool on per PON port basis.
1296 // Since this situation is tricky, as a hack, we pass the NNI port
1297 // index (network_intf_id) as PON port Index for the flow_id resource
1298 // pool. Also, there is no ONU Id available for trapping LLDP packets
1299 // on NNI port, use onu_id as -1 (invalid)
1300 // ****************** CAVEAT *******************
1301 // This logic works if the NNI Port Id falls within the same valid
1302 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1303 // we need to have a re-look at this.
1304 // *********************************************
1305
1306 var onuID = -1
1307 var uniID = -1
1308 var gemPortID = -1
1309
David K. Bainbridge794735f2020-02-11 21:01:37 -08001310 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1311 if err != nil {
1312 return NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
1313 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001314 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301315 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001316 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001317 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001318 }
npujarec5762e2020-01-01 14:08:48 +05301319 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001320
1321 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001322 return NewErrNotFound("flow-id", log.Fields{
1323 "interface-id": networkInterfaceID,
1324 "onu-id": onuID,
1325 "uni-id": uniID,
1326 "gem-port-id": gemPortID,
1327 "cookie": flowStoreCookie},
1328 err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001329 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001330 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1331 if err != nil {
1332 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001333 }
1334 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001335 actionProto, err := makeOpenOltActionField(actionInfo)
1336 if err != nil {
1337 return NewErrInvalidValue(log.Fields{"action": actionInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001338 }
1339 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1340
1341 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1342 OnuId: int32(onuID), // OnuId not required
1343 UniId: int32(uniID), // UniId not used
1344 FlowId: flowID,
1345 FlowType: Downstream,
1346 NetworkIntfId: int32(networkInterfaceID),
1347 GemportId: int32(gemPortID),
1348 Classifier: classifierProto,
1349 Action: actionProto,
1350 Priority: int32(flow.Priority),
1351 Cookie: flow.Cookie,
1352 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001353 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
1354 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001355 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001356 log.Debug("LLDP trap on NNI flow added to device successfully")
1357 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1358 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1359 int32(onuID),
1360 int32(uniID),
1361 flowID, flowsToKVStore); err != nil {
1362 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
1363 }
1364 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301365}
1366
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301367func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001368 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1369}
1370
1371//getOnuChildDevice to fetch onu
1372func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1373 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1374 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001375 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1376 if err != nil {
1377 return nil, NewErrNotFound("onu", log.Fields{
1378 "interface-id": parentPortNo,
1379 "onu-id": onuID},
1380 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301381 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301382 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1383 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301384}
1385
1386func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001387 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301388 return nil
1389}
1390
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001391func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1392 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301393}
1394
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001395func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001396 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001397 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001398 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001399 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001400}
1401
Girish Gowdra6b130582019-11-20 16:45:20 +05301402func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1403 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1404 if err != nil {
1405 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1406 return err
1407 }
1408
1409 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1410 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1411 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1412 delGemPortMsg,
1413 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1414 f.deviceHandler.deviceType,
1415 onuDevice.Type,
1416 onuDevice.Id,
1417 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1418 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1419 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1420 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1421 return sendErr
1422 }
1423 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1424 return nil
1425}
1426
1427func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1428 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1429 if err != nil {
1430 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1431 return err
1432 }
1433
1434 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1435 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1436 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1437 delTcontMsg,
1438 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1439 f.deviceHandler.deviceType,
1440 onuDevice.Type,
1441 onuDevice.Id,
1442 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1443 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1444 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1445 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1446 return sendErr
1447 }
1448 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1449 return nil
1450}
1451
Girish Gowdra3d633032019-12-10 16:37:05 +05301452func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1453 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1454 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1455 if val.(int) > 0 {
1456 pnFlDels := val.(int) - 1
1457 if pnFlDels > 0 {
1458 log.Debugw("flow delete succeeded, more pending",
1459 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1460 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1461 } else {
1462 log.Debugw("all pending flow deletes handled, removing entry from map",
1463 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1464 f.pendingFlowDelete.Delete(pnFlDelKey)
1465 }
1466 }
1467 } else {
1468 log.Debugw("no pending delete flows found",
1469 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1470
1471 }
1472
1473}
1474
Girish Gowdrac3037402020-01-22 20:29:53 +05301475// Once the gemport is released for a given onu, it also has to be cleared from local cache
1476// which was used for deriving the gemport->logicalPortNo during packet-in.
1477// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1478// is conveyed to ONOS during packet-in OF message.
1479func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1480 f.lockCache.Lock()
1481 defer f.lockCache.Unlock()
1482 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001483 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301484 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001485 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301486 // If the gemport is found, delete it from local cache.
1487 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001488 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1489 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301490 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001491 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301492 break
1493 }
1494 }
1495 break
1496 }
1497 }
1498}
1499
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301500//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301501func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301502 gemPortID int32, flowID uint32, flowDirection string,
1503 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001504
Chaitrashree G S90a17952019-11-14 21:51:21 -05001505 tpID, err := getTpIDFromFlow(flow)
1506 if err != nil {
1507 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1508 return err
1509 }
Gamze Abakafee36392019-10-03 11:17:24 +00001510
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001511 if len(updatedFlows) >= 0 {
1512 // There are still flows referencing the same flow_id.
1513 // So the flow should not be freed yet.
1514 // For ex: Case of HSIA where same flow is shared
1515 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301516 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001517 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301518 // Do this for subscriber flows only (not trap from NNI flows)
1519 if onuID != -1 && uniID != -1 {
1520 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1521 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1522 log.Debugw("creating entry for pending flow delete",
1523 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1524 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1525 } else {
1526 pnFlDels := val.(int) + 1
1527 log.Debugw("updating flow delete entry",
1528 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1529 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1530 }
1531
1532 defer f.deletePendingFlows(Intf, onuID, uniID)
1533 }
1534
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301535 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301536 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001537
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301538 uni := getUniPortPath(Intf, onuID, uniID)
1539 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001540 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301541 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001542 if err != nil { // This should not happen, something wrong in KV backend transaction
1543 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301544 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001545 }
1546 if techprofileInst == nil {
1547 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301548 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001549 }
1550
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301551 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001552 if f.isGemPortUsedByAnotherFlow(gemPK) {
1553 flowIDs := f.flowsUsedByGemPort[gemPK]
1554 for i, flowIDinMap := range flowIDs {
1555 if flowIDinMap == flowID {
1556 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301557 // everytime flowsUsedByGemPort cache is updated the same should be updated
1558 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001559 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301560 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001561 break
1562 }
1563 }
1564 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301565 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001566 }
Gamze Abakafee36392019-10-03 11:17:24 +00001567 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301568 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001569 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1570 // 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 +05301571 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301572 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001573 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301574 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1575 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001576 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301577 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1578 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001579 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301580 // Delete the gem port on the ONU.
1581 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1582 log.Errorw("error processing delete gem-port towards onu",
1583 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1584 }
Gamze Abakafee36392019-10-03 11:17:24 +00001585
npujarec5762e2020-01-01 14:08:48 +05301586 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001587 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301588 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1589 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1590 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1591 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1592 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301593 // Delete the TCONT on the ONU.
1594 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1595 log.Errorw("error processing delete tcont towards onu",
1596 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1597 }
Gamze Abakafee36392019-10-03 11:17:24 +00001598 }
1599 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001600 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301601 return nil
1602}
1603
David K. Bainbridge794735f2020-02-11 21:01:37 -08001604// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301605func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301606
1607 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001608
1609 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301610 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001611 return
1612 }
1613
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301614 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301615 classifierInfo := make(map[string]interface{})
1616
1617 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1618 if err != nil {
1619 log.Error(err)
1620 return
1621 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301622
David K. Bainbridge794735f2020-02-11 21:01:37 -08001623 onuID := int32(onu)
1624 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301625
1626 for _, field := range flows.GetOfbFields(flow) {
1627 if field.Type == flows.IP_PROTO {
1628 classifierInfo[IPProto] = field.GetIpProto()
1629 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1630 }
1631 }
1632 log.Debugw("Extracted access info from flow to be deleted",
1633 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1634
1635 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1636 onuID = -1
1637 uniID = -1
1638 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001639 Intf, err = IntfIDFromNniPortNum(inPort)
1640 if err != nil {
1641 log.Errorw("invalid-in-port-number",
1642 log.Fields{
1643 "port-number": inPort,
1644 "error": err})
1645 return
1646 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301647 }
npujarec5762e2020-01-01 14:08:48 +05301648 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001649 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301650 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301651 if flowInfo == nil {
1652 log.Debugw("No FlowInfo found found in KV store",
1653 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1654 return
1655 }
1656 updatedFlows = nil
1657 for _, flow := range *flowInfo {
1658 updatedFlows = append(updatedFlows, flow)
1659 }
1660
1661 for i, storedFlow := range updatedFlows {
1662 if flow.Id == storedFlow.LogicalFlowID {
1663 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1664 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001665 // DKB
1666 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1667 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1668 return
1669 }
1670 log.Debug("Flow removed from device successfully")
1671 //Remove the Flow from FlowInfo
1672 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1673 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1674 flowID, flowDirection, portNum, updatedFlows); err != nil {
1675 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301676 return
1677 }
1678 }
1679 }
1680 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001681}
1682
Esin Karamanccb714b2019-11-29 15:02:06 +00001683//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1684// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301685func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001686 classifierInfo := make(map[string]interface{})
1687 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301688 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001689
1690 if err != nil {
1691 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1692 return
1693 }
1694
David K. Bainbridge794735f2020-02-11 21:01:37 -08001695 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1696 if err != nil {
1697 // DKB
1698 log.Errorw("invalid-in-port-number",
1699 log.Fields{
1700 "port-number": inPort,
1701 "error": err})
1702 return
1703 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001704 var onuID = int32(NoneOnuID)
1705 var uniID = int32(NoneUniID)
1706 var flowID uint32
1707 var updatedFlows []rsrcMgr.FlowInfo
1708
npujarec5762e2020-01-01 14:08:48 +05301709 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001710
1711 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301712 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001713 if flowInfo == nil {
1714 log.Debugw("No multicast FlowInfo found in the KV store",
1715 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1716 continue
1717 }
1718 updatedFlows = nil
1719 for _, flow := range *flowInfo {
1720 updatedFlows = append(updatedFlows, flow)
1721 }
1722 for i, storedFlow := range updatedFlows {
1723 if flow.Id == storedFlow.LogicalFlowID {
1724 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1725 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1726 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001727 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1728 // DKB
1729 log.Errorw("failed-to-remove-multicast-flow",
1730 log.Fields{
1731 "flow-id": flow.Id,
1732 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001733 return
1734 }
1735 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1736 //Remove the Flow from FlowInfo
1737 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301738 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001739 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1740 return
1741 }
1742 //release flow id
1743 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301744 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001745 }
1746 }
1747 }
1748}
1749
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001750//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301751func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001752 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301753 var direction string
1754 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001755
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301756 for _, action := range flows.GetActions(flow) {
1757 if action.Type == flows.OUTPUT {
1758 if out := action.GetOutput(); out != nil {
1759 actionInfo[Output] = out.GetPort()
1760 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1761 } else {
1762 log.Error("Invalid output port in action")
1763 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001764 }
1765 }
1766 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001767
1768 if flows.HasGroup(flow) {
1769 direction = Multicast
1770 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301771 direction = Upstream
1772 } else {
1773 direction = Downstream
1774 }
npujarec5762e2020-01-01 14:08:48 +05301775 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301776
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001777 return
1778}
1779
Girish Gowdra3d633032019-12-10 16:37:05 +05301780func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1781 uniID uint32, ch chan bool) {
1782 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1783 for {
1784 select {
1785 case <-time.After(20 * time.Millisecond):
1786 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1787 log.Debug("pending flow deletes completed")
1788 ch <- true
1789 return
1790 }
1791 case <-ctx.Done():
1792 log.Error("flow delete wait handler routine canceled")
1793 return
1794 }
1795 }
1796}
1797
Esin Karamanae41e2b2019-12-17 18:13:13 +00001798//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1799func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1800 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1801 if ethType, ok := classifierInfo[EthType]; ok {
1802 if ethType.(uint32) == IPv4EthType {
1803 if ipProto, ok := classifierInfo[IPProto]; ok {
1804 if ipProto.(uint32) == IgmpProto {
1805 return true
1806 }
1807 }
1808 }
1809 }
1810 }
1811 return false
1812}
1813
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001814// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301815// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301816func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001817 classifierInfo := make(map[string]interface{})
1818 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001819 var UsMeterID uint32
1820 var DsMeterID uint32
1821
1822 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001823 formulateClassifierInfoFromFlow(classifierInfo, flow)
1824
1825 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1826 if err != nil {
1827 // Error logging is already done in the called function
1828 // So just return in case of error
1829 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301830 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001831
Esin Karamanccb714b2019-11-29 15:02:06 +00001832 if flows.HasGroup(flow) {
1833 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301834 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001835 return
1836 }
1837
manikkaraj k17652a72019-05-06 09:06:36 -04001838 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001839 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1840 if err != nil {
1841 // error if any, already logged in the called function
1842 return
manikkaraj k17652a72019-05-06 09:06:36 -04001843 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001844
David K. Bainbridge82efc492019-09-04 09:57:11 -07001845 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1846 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001847
Humera Kouser94d7a842019-08-25 19:04:32 -04001848 if ethType, ok := classifierInfo[EthType]; ok {
1849 if ethType.(uint32) == LldpEthType {
1850 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301851 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001852 return
1853 }
1854 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001855 if ipProto, ok := classifierInfo[IPProto]; ok {
1856 if ipProto.(uint32) == IPProtoDhcp {
1857 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301858 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001859 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301860 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001861 return
1862 }
1863 }
1864 }
1865 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001866 if isIgmpTrapDownstreamFlow(classifierInfo) {
1867 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301868 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001869 return
1870 }
A R Karthick1f85b802019-10-11 05:06:05 +00001871
1872 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301873 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001874
Chaitrashree G S90a17952019-11-14 21:51:21 -05001875 TpID, err := getTpIDFromFlow(flow)
1876 if err != nil {
1877 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1878 return
1879 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001880 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001881 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001882 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001883 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1884 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001885 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001886 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1887
1888 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301889
1890 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1891 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1892 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 +05301893 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301894 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301895 pendingFlowDelComplete := make(chan bool)
1896 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1897 select {
1898 case <-pendingFlowDelComplete:
1899 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301900 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301901
1902 case <-time.After(10 * time.Second):
1903 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1904 }
1905 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001906}
1907
Esin Karamanccb714b2019-11-29 15:02:06 +00001908// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001909func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001910 classifierInfo[PacketTagType] = DoubleTag
1911 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1912
npujarec5762e2020-01-01 14:08:48 +05301913 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001914 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001915 return NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001916 }
1917 //replace ipDst with ethDst
1918 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1919 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1920 // replace ipv4_dst classifier with eth_dst
1921 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1922 delete(classifierInfo, Ipv4Dst)
1923 delete(classifierInfo, EthType)
1924 classifierInfo[EthDst] = multicastMac
1925 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1926 }
1927
David K. Bainbridge794735f2020-02-11 21:01:37 -08001928 onuID := NoneOnuID
1929 uniID := NoneUniID
1930 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001931
David K. Bainbridge794735f2020-02-11 21:01:37 -08001932 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1933 if err != nil {
1934 return NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
1935 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001936
David K. Bainbridge794735f2020-02-11 21:01:37 -08001937 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301938 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001939 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1940 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001941 }
npujarec5762e2020-01-01 14:08:48 +05301942 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001943 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001944 return NewErrNotFound("multicast-flow-id", log.Fields{
1945 "interface-id": networkInterfaceID,
1946 "onu-id": onuID,
1947 "uni-id": uniID,
1948 "gem-port-id": gemPortID,
1949 "cookie": flowStoreCookie},
1950 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001951 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001952 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1953 if err != nil {
1954 return NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001955 }
1956 groupID := actionInfo[GroupID].(uint32)
1957 multicastFlow := openoltpb2.Flow{
1958 FlowId: flowID,
1959 FlowType: Multicast,
1960 NetworkIntfId: int32(networkInterfaceID),
1961 GroupId: groupID,
1962 Classifier: classifierProto,
1963 Priority: int32(flow.Priority),
1964 Cookie: flow.Cookie}
1965
David K. Bainbridge794735f2020-02-11 21:01:37 -08001966 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
1967 return NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1968 }
1969 log.Debug("multicast flow added to device successfully")
1970 //get cached group
1971 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1972 if err == nil {
1973 //calling groupAdd to set group members after multicast flow creation
1974 if f.ModifyGroup(ctx, group) {
1975 //cached group can be removed now
1976 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001977 }
1978 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001979
1980 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1981 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1982 int32(onuID),
1983 int32(uniID),
1984 flowID, flowsToKVStore); err != nil {
1985 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
1986 }
1987 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001988}
1989
1990//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301991func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001992 if _, ok := classifierInfo[InPort]; ok {
1993 return classifierInfo[InPort].(uint32), nil
1994 }
1995 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301996 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001997 if e == nil && len(nniPorts) > 0 {
1998 return nniPorts[0], nil
1999 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002000 return 0, NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002001}
2002
2003// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05302004func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00002005 log.Infow("add-group", log.Fields{"group": group})
2006 if group == nil {
2007 log.Warn("skipping nil group")
2008 return
2009 }
2010
2011 groupToOlt := openoltpb2.Group{
2012 GroupId: group.Desc.GroupId,
2013 Command: openoltpb2.Group_SET_MEMBERS,
2014 Action: f.buildGroupAction(),
2015 }
2016
2017 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302018 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002019 if err != nil {
2020 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
2021 return
2022 }
2023 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302024 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002025 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
2026 } else {
2027 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2028 }
2029}
2030
2031//buildGroupAction creates and returns a group action
2032func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2033 var actionCmd openoltpb2.ActionCmd
2034 var action openoltpb2.Action
2035 action.Cmd = &actionCmd
2036 //pop outer vlan
2037 action.Cmd.RemoveOuterTag = true
2038 return &action
2039}
2040
2041// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05302042func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00002043 log.Infow("modify-group", log.Fields{"group": group})
2044 if group == nil || group.Desc == nil {
2045 log.Warn("cannot modify group; group is nil")
2046 return false
2047 }
2048
2049 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2050 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302051 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002052
2053 if err != nil {
2054 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2055 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2056 return false
2057 }
2058
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002059 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002060 if groupExists {
2061 // group already exists
2062 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002063 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002064 } else {
2065 current = f.buildGroup(group.Desc.GroupId, nil)
2066 }
2067
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002068 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2069 // get members to be added
2070 membersToBeAdded := f.findDiff(current, new)
2071 // get members to be removed
2072 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002073
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002074 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2075 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002076
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002077 groupToOlt := openoltpb2.Group{
2078 GroupId: group.Desc.GroupId,
2079 }
2080 var added, removed = true, true
2081 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2082 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2083 groupToOlt.Members = membersToBeAdded
2084 //execute addMembers
2085 added = f.callGroupAddRemove(&groupToOlt)
2086 }
2087 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2088 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2089 groupToOlt.Members = membersToBeRemoved
2090 //execute removeMembers
2091 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002092 }
2093
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002094 //save the modified group
2095 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302096 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002097 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2098 }
2099 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002100 } else {
2101 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2102 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002103 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002104 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002105}
2106
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002107//callGroupAddRemove performs add/remove buckets operation for the indicated group
2108func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2109 if err := f.performGroupOperation(group); err != nil {
2110 st, _ := status.FromError(err)
2111 //ignore already exists error code
2112 if st.Code() != codes.AlreadyExists {
2113 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002114 }
2115 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002116 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002117}
2118
2119//findDiff compares group members and finds members which only exists in groups2
2120func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2121 var members []*openoltpb2.GroupMember
2122 for _, bucket := range group2.Members {
2123 if !f.contains(group1.Members, bucket) {
2124 // bucket does not exist and must be added
2125 members = append(members, bucket)
2126 }
2127 }
2128 return members
2129}
2130
2131//contains returns true if the members list contains the given member; false otherwise
2132func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2133 for _, groupMember := range members {
2134 if groupMember.InterfaceId == member.InterfaceId {
2135 return true
2136 }
2137 }
2138 return false
2139}
2140
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002141//performGroupOperation call performGroupOperation operation of openolt proto
2142func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002143 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2144 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2145 if err != nil {
2146 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2147 }
2148 return err
2149}
2150
2151//buildGroup build openoltpb2.Group from given group id and bucket list
2152func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2153 group := openoltpb2.Group{
2154 GroupId: groupID}
2155 // create members of the group
2156 if buckets != nil {
2157 for _, ofBucket := range buckets {
2158 member := f.buildMember(ofBucket)
2159 if member != nil && !f.contains(group.Members, member) {
2160 group.Members = append(group.Members, member)
2161 }
2162 }
2163 }
2164 return &group
2165}
2166
2167//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2168func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2169 var outPort uint32
2170 outPortFound := false
2171 for _, ofAction := range ofBucket.Actions {
2172 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2173 outPort = ofAction.GetOutput().Port
2174 outPortFound = true
2175 }
2176 }
2177
2178 if !outPortFound {
2179 log.Debugw("bucket skipped since no out port found in it",
2180 log.Fields{"ofBucket": ofBucket})
2181 return nil
2182 }
2183 interfaceID := IntfIDFromUniPortNum(outPort)
2184 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2185 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2186 member := openoltpb2.GroupMember{
2187 InterfaceId: interfaceID,
2188 InterfaceType: openoltpb2.GroupMember_PON,
2189 GemPortId: groupInfo.gemPortID,
2190 Priority: groupInfo.servicePriority,
2191 }
2192 //add member to the group
2193 return &member
2194 }
2195 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2196 log.Fields{"ofBucket": ofBucket})
2197 return nil
2198}
2199
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002200//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002201func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002202
2203 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302204 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002205 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302206 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302207 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302208 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002209
Manikkaraj kb1d51442019-07-23 10:41:02 -04002210 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002211 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002212 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2213 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2214 tpDownloadMsg,
2215 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2216 f.deviceHandler.deviceType,
2217 onuDevice.Type,
2218 onuDevice.Id,
2219 onuDevice.ProxyAddress.DeviceId, "")
2220 if sendErr != nil {
2221 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2222 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2223 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2224 return sendErr
2225 }
2226 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302227 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302228}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002229
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302230//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302231func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302232
2233 f.lockCache.Lock()
2234 defer f.lockCache.Unlock()
2235 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2236 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002237 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2238 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302239 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2240 return
2241 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002242 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2243}
2244
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302245//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302246func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302247 f.lockCache.Lock()
2248 defer f.lockCache.Unlock()
2249 onugem := f.onuGemInfo[intfID]
2250 // update the gem to the local cache as well as to kv strore
2251 for idx, onu := range onugem {
2252 if onu.OnuID == onuID {
2253 // check if gem already exists , else update the cache and kvstore
2254 for _, gem := range onu.GemPorts {
2255 if gem == gemPort {
2256 log.Debugw("Gem already in cache, no need to update cache and kv store",
2257 log.Fields{"gem": gemPort})
2258 return
2259 }
2260 }
2261 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2262 f.onuGemInfo[intfID] = onugem
2263 }
2264 }
npujarec5762e2020-01-01 14:08:48 +05302265 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302266 if err != nil {
2267 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002268 return
2269 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002270}
2271
2272// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002273
2274//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2275func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302276
2277 f.lockCache.Lock()
2278 defer f.lockCache.Unlock()
2279
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002280 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 +05302281 // get onuid from the onugem info cache
2282 onugem := f.onuGemInfo[intfID]
2283 for _, onu := range onugem {
2284 for _, gem := range onu.GemPorts {
2285 if gem == gemPortID {
2286 return onu.OnuID, nil
2287 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002288 }
2289 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002290 return uint32(0), NewErrNotFound("onu-id", log.Fields{
2291 "serial-number": serialNumber,
2292 "interface-id": intfID,
2293 "gem-port-id": gemPortID},
2294 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002295}
2296
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002297//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302298func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002299 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002300 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002301 var err error
2302
2303 if packetIn.IntfType == "pon" {
2304 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002305 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002306 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2307 return logicalPortNum, err
2308 }
2309 if packetIn.PortNo != 0 {
2310 logicalPortNum = packetIn.PortNo
2311 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002312 uniID := uint32(0) // FIXME - multi-uni support
2313 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002314 }
2315 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302316 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002317 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002318 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002319 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002320 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2321 "logicalPortNum": logicalPortNum,
2322 "IntfType": packetIn.IntfType,
2323 "packet": hex.EncodeToString(packetIn.Pkt),
2324 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002325 return logicalPortNum, nil
2326}
2327
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002328//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302329func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002330 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002331 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302332
2333 f.lockCache.Lock()
2334 defer f.lockCache.Unlock()
2335 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2336
2337 gemPortID, ok := f.packetInGemPort[pktInkey]
2338 if ok {
2339 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2340 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002341 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302342 //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 +05302343 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302344 if err == nil {
2345 if gemPortID != 0 {
2346 f.packetInGemPort[pktInkey] = gemPortID
2347 log.Debugw("Found gem port from kv store and updating cache with gemport",
2348 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2349 return gemPortID, nil
2350 }
2351 }
2352 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2353 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002354}
2355
npujarec5762e2020-01-01 14:08:48 +05302356func installFlowOnAllGemports(ctx context.Context,
2357 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002358 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002359 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302360 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302361 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302362 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302363 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002364 args map[string]uint32,
2365 classifier map[string]interface{}, action map[string]interface{},
2366 logicalFlow *ofp.OfpFlowStats,
2367 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302368 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002369 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002370 vlanID ...uint32) {
2371 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302372
2373 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2374 var gemPortID uint32
2375 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2376 // We need to trim prefix "0b", before further processing
2377 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2378 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2379 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2380 // If a particular character in the string is set to '1', identify the index of this character from
2381 // the LSB position which marks the PCP bit consumed by the given gem port.
2382 // This PCP bit now becomes a classifier in the flow.
2383 if pbitSet == BinaryBit1 {
2384 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2385 gemPortID = gemPortAttribute.GemportID
2386 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2387 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2388 } else if FlowType == EapolFlow {
2389 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2390 } else {
2391 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2392 return
2393 }
2394 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002395 }
2396 }
2397}
2398
David K. Bainbridge794735f2020-02-11 21:01:37 -08002399func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002400 log.Debug("Adding trap-dhcp-of-nni-flow")
2401 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002402 classifier[PacketTagType] = DoubleTag
2403 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002404 /* We manage flowId resource pool on per PON port basis.
2405 Since this situation is tricky, as a hack, we pass the NNI port
2406 index (network_intf_id) as PON port Index for the flowId resource
2407 pool. Also, there is no ONU Id available for trapping DHCP packets
2408 on NNI port, use onu_id as -1 (invalid)
2409 ****************** CAVEAT *******************
2410 This logic works if the NNI Port Id falls within the same valid
2411 range of PON Port Ids. If this doesn't work for some OLT Vendor
2412 we need to have a re-look at this.
2413 *********************************************
2414 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002415 onuID := -1
2416 uniID := -1
2417 gemPortID := -1
2418 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002419 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302420 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002421 return NewErrNotFound("nni-intreface-id", log.Fields{
2422 "classifier": classifier,
2423 "action": action},
2424 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302425 }
2426
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002427 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302428 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002429 log.Debug("Flow-exists-not-re-adding")
2430 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002431 }
npujarec5762e2020-01-01 14:08:48 +05302432 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002433 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002434 return NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
2435 "interface-id": networkInterfaceID,
2436 "onu-id": onuID,
2437 "uni-id": uniID,
2438 "gem-port-id": gemPortID,
2439 "cookie": flowStoreCookie},
2440 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002441 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002442 classifierProto, err := makeOpenOltClassifierField(classifier)
2443 if err != nil {
2444 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002445 }
2446 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002447 actionProto, err := makeOpenOltActionField(action)
2448 if err != nil {
2449 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002450 }
2451 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002452 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2453 OnuId: int32(onuID), // OnuId not required
2454 UniId: int32(uniID), // UniId not used
2455 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002456 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002457 AllocId: int32(allocID), // AllocId not used
2458 NetworkIntfId: int32(networkInterfaceID),
2459 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002460 Classifier: classifierProto,
2461 Action: actionProto,
2462 Priority: int32(logicalFlow.Priority),
2463 Cookie: logicalFlow.Cookie,
2464 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002465 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2466 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002467 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002468 log.Debug("DHCP trap on NNI flow added to device successfully")
2469 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2470 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2471 int32(onuID),
2472 int32(uniID),
2473 flowID, flowsToKVStore); err != nil {
2474 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2475 }
2476 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002477}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002478
Esin Karamanae41e2b2019-12-17 18:13:13 +00002479//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2480func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2481 var packetType string
2482 ovid, ivid := false, false
2483 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2484 vid := vlanID & VlanvIDMask
2485 if vid != ReservedVlan {
2486 ovid = true
2487 }
2488 }
2489 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2490 vid := uint32(metadata)
2491 if vid != ReservedVlan {
2492 ivid = true
2493 }
2494 }
2495 if ovid && ivid {
2496 packetType = DoubleTag
2497 } else if !ovid && !ivid {
2498 packetType = Untagged
2499 } else {
2500 packetType = SingleTag
2501 }
2502 return packetType
2503}
2504
2505//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002506func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002507 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2508 action := make(map[string]interface{})
2509 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2510 action[TrapToHost] = true
2511 /* We manage flowId resource pool on per PON port basis.
2512 Since this situation is tricky, as a hack, we pass the NNI port
2513 index (network_intf_id) as PON port Index for the flowId resource
2514 pool. Also, there is no ONU Id available for trapping packets
2515 on NNI port, use onu_id as -1 (invalid)
2516 ****************** CAVEAT *******************
2517 This logic works if the NNI Port Id falls within the same valid
2518 range of PON Port Ids. If this doesn't work for some OLT Vendor
2519 we need to have a re-look at this.
2520 *********************************************
2521 */
2522 onuID := -1
2523 uniID := -1
2524 gemPortID := -1
2525 allocID := -1
2526 networkInterfaceID, err := getNniIntfID(classifier, action)
2527 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002528 return NewErrNotFound("nni-interface-id", log.Fields{
2529 "classifier": classifier,
2530 "action": action},
2531 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002532 }
2533 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302534 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002535 log.Debug("igmp-flow-exists-not-re-adding")
2536 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002537 }
npujarec5762e2020-01-01 14:08:48 +05302538 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002539 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002540 return NewErrNotFound("igmp-flow-id", log.Fields{
2541 "interface-id": networkInterfaceID,
2542 "onu-id": onuID,
2543 "uni-id": uniID,
2544 "gem-port-id": gemPortID,
2545 "cookie": flowStoreCookie},
2546 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002547 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002548 classifierProto, err := makeOpenOltClassifierField(classifier)
2549 if err != nil {
2550 return NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002551 }
2552 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002553 actionProto, err := makeOpenOltActionField(action)
2554 if err != nil {
2555 return NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002556 }
2557 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2558 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2559 OnuId: int32(onuID), // OnuId not required
2560 UniId: int32(uniID), // UniId not used
2561 FlowId: flowID,
2562 FlowType: Downstream,
2563 AllocId: int32(allocID), // AllocId not used
2564 NetworkIntfId: int32(networkInterfaceID),
2565 GemportId: int32(gemPortID), // GemportId not used
2566 Classifier: classifierProto,
2567 Action: actionProto,
2568 Priority: int32(logicalFlow.Priority),
2569 Cookie: logicalFlow.Cookie,
2570 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002571 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
2572 return NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002573 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002574 log.Debug("IGMP Trap on NNI flow added to device successfully")
2575 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2576 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2577 int32(onuID),
2578 int32(uniID),
2579 flowID, flowsToKVStore); err != nil {
2580 return NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
2581 }
2582 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002583}
2584
salmansiddiqui7ac62132019-08-22 03:58:50 +00002585func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2586 if MeterID == 0 { // This should never happen
David K. Bainbridge794735f2020-02-11 21:01:37 -08002587 return "", NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002588 }
2589 if Dir == tp_pb.Direction_UPSTREAM {
2590 return "upstream", nil
2591 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2592 return "downstream", nil
2593 }
2594 return "", nil
2595}
2596
npujarec5762e2020-01-01 14:08:48 +05302597func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002598 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2599 TpID uint32, uni string) {
2600 var gemPort uint32
2601 intfID := args[IntfID]
2602 onuID := args[OnuID]
2603 uniID := args[UniID]
2604 portNo := args[PortNo]
2605 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002606 if ipProto, ok := classifierInfo[IPProto]; ok {
2607 if ipProto.(uint32) == IPProtoDhcp {
2608 log.Info("Adding DHCP flow")
2609 if pcp, ok := classifierInfo[VlanPcp]; ok {
2610 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2611 tp_pb.Direction_UPSTREAM,
2612 pcp.(uint32))
2613 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302614 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002615 } else {
2616 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302617 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002618 }
2619
2620 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002621 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2622 if pcp, ok := classifierInfo[VlanPcp]; ok {
2623 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2624 tp_pb.Direction_UPSTREAM,
2625 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302626 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002627 } else {
2628 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302629 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002630 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002631 } else {
2632 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2633 return
2634 }
2635 } else if ethType, ok := classifierInfo[EthType]; ok {
2636 if ethType.(uint32) == EapEthType {
2637 log.Info("Adding EAPOL flow")
2638 var vlanID uint32
2639 if val, ok := classifierInfo[VlanVid]; ok {
2640 vlanID = (val.(uint32)) & VlanvIDMask
2641 } else {
2642 vlanID = DefaultMgmtVlan
2643 }
2644 if pcp, ok := classifierInfo[VlanPcp]; ok {
2645 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2646 tp_pb.Direction_UPSTREAM,
2647 pcp.(uint32))
2648
Girish Gowdrafae935c2020-02-17 19:21:44 +05302649 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002650 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302651 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002652 }
2653 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002654 } else if _, ok := actionInfo[PushVlan]; ok {
2655 log.Info("Adding upstream data rule")
2656 if pcp, ok := classifierInfo[VlanPcp]; ok {
2657 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2658 tp_pb.Direction_UPSTREAM,
2659 pcp.(uint32))
2660 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302661 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002662 } else {
2663 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302664 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002665 }
2666 } else if _, ok := actionInfo[PopVlan]; ok {
2667 log.Info("Adding Downstream data rule")
2668 if pcp, ok := classifierInfo[VlanPcp]; ok {
2669 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002670 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002671 pcp.(uint32))
2672 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302673 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002674 } else {
2675 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302676 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002677 }
2678 } else {
2679 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2680 return
2681 }
2682 // Send Techprofile download event to child device in go routine as it takes time
2683 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2684}
2685
Gamze Abakafee36392019-10-03 11:17:24 +00002686func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2687 flowIDList := f.flowsUsedByGemPort[gemPK]
2688 if len(flowIDList) > 1 {
2689 return true
2690 }
2691 return false
2692}
2693
npujarec5762e2020-01-01 14:08:48 +05302694func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2695 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002696 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2697 for _, currentGemPort := range currentGemPorts {
2698 for _, tpGemPort := range tpGemPorts {
2699 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2700 return true, currentGemPort
2701 }
2702 }
2703 }
Girish Gowdra54934262019-11-13 14:19:55 +05302704 if tpInst.InstanceCtrl.Onu == "single-instance" {
2705 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302706 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2707 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302708
2709 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2710 // still be used on other uni ports.
2711 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2712 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302713 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302714 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302715 for i := 0; i < len(tpInstances); i++ {
2716 tpI := tpInstances[i]
2717 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302718 for _, tpGemPort := range tpGemPorts {
2719 if tpGemPort.GemportID != gemPortID {
2720 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2721 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302722 }
2723 }
2724 }
2725 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302726 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002727 return false, 0
2728}
2729
salmansiddiqui7ac62132019-08-22 03:58:50 +00002730func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002731 for _, field := range flows.GetOfbFields(flow) {
2732 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002733 classifierInfo[EthType] = field.GetEthType()
2734 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002735 } else if field.Type == flows.ETH_DST {
2736 classifierInfo[EthDst] = field.GetEthDst()
2737 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002738 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002739 classifierInfo[IPProto] = field.GetIpProto()
2740 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002741 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002742 classifierInfo[InPort] = field.GetPort()
2743 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002744 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302745 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002746 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002747 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002748 classifierInfo[VlanPcp] = field.GetVlanPcp()
2749 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002750 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002751 classifierInfo[UDPDst] = field.GetUdpDst()
2752 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002753 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002754 classifierInfo[UDPSrc] = field.GetUdpSrc()
2755 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002756 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002757 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2758 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002759 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002760 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2761 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002762 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002763 classifierInfo[Metadata] = field.GetTableMetadata()
2764 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002765 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002766 classifierInfo[TunnelID] = field.GetTunnelId()
2767 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2768 } else {
2769 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2770 return
2771 }
2772 }
2773}
2774
2775func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002776 for _, action := range flows.GetActions(flow) {
2777 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002778 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002779 actionInfo[Output] = out.GetPort()
2780 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002781 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002782 return NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002783 }
Scott Baker355d1742019-10-24 10:57:52 -07002784 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002785 actionInfo[PopVlan] = true
2786 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002787 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002788 if out := action.GetPush(); out != nil {
2789 if tpid := out.GetEthertype(); tpid != 0x8100 {
2790 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2791 } else {
2792 actionInfo[PushVlan] = true
2793 actionInfo[TPID] = tpid
2794 log.Debugw("action-type-push-vlan",
2795 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2796 }
2797 }
Scott Baker355d1742019-10-24 10:57:52 -07002798 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002799 if out := action.GetSetField(); out != nil {
2800 if field := out.GetField(); field != nil {
2801 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002802 return NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002803 }
2804 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002805 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002806 }
2807 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002808 } else if action.Type == flows.GROUP {
2809 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002810 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002811 return NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002812 }
2813 }
2814 return nil
2815}
2816
Esin Karamanccb714b2019-11-29 15:02:06 +00002817func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2818 if ofbField := field.GetOfbField(); ofbField != nil {
2819 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2820 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2821 actionInfo[VlanVid] = vlan & 0xfff
2822 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2823 } else {
2824 log.Error("No Invalid vlan id in set vlan-vid action")
2825 }
2826 } else {
2827 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2828 }
2829 }
2830}
2831
2832func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2833 if action.GetGroup() == nil {
2834 log.Warn("No group entry found in the group action")
2835 } else {
2836 actionInfo[GroupID] = action.GetGroup().GroupId
2837 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2838 }
2839}
2840
salmansiddiqui7ac62132019-08-22 03:58:50 +00002841func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002842 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002843 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2844 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2845 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002846 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002847 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002848 log.Debugw("upstream pon-to-controller-flow,inport-in-tunnelid", log.Fields{"newInPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002849 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002850 return NewErrNotFound("child-in-port", log.Fields{
2851 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2852 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002853 }
2854 }
2855 } else {
2856 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2857 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002858 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002859 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002860 actionInfo[Output] = uniPort
2861 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 +00002862 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002863 return NewErrNotFound("out-port", log.Fields{
2864 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2865 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002866 }
2867 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2868 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002869 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002870 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002871 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2872 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002873 } else {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002874 return NewErrNotFound("nni-port", log.Fields{
2875 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2876 "in-port": classifierInfo[InPort].(uint32),
2877 "out-port": actionInfo[Output].(uint32),
2878 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002879 }
2880 }
2881 }
2882 return nil
2883}
Gamze Abakafee36392019-10-03 11:17:24 +00002884
Chaitrashree G S90a17952019-11-14 21:51:21 -05002885func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002886 /* Metadata 8 bytes:
2887 Most Significant 2 Bytes = Inner VLAN
2888 Next 2 Bytes = Tech Profile ID(TPID)
2889 Least Significant 4 Bytes = Port ID
2890 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2891 subscriber related flows.
2892 */
2893 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2894 if metadata == 0 {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002895 return 0, NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002896 }
2897 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002898 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002899}
2900
2901func appendUnique(slice []uint32, item uint32) []uint32 {
2902 for _, sliceElement := range slice {
2903 if sliceElement == item {
2904 return slice
2905 }
2906 }
2907 return append(slice, item)
2908}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302909
2910// getNniIntfID gets nni intf id from the flow classifier/action
2911func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2912
2913 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2914 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002915 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2916 if err != nil {
2917 log.Debugw("invalid-action-port-number",
2918 log.Fields{
2919 "port-number": action[Output].(uint32),
2920 "error": err})
2921 return uint32(0), err
2922 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302923 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2924 return intfID, nil
2925 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002926 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2927 if err != nil {
2928 log.Debugw("invalid-classifier-port-number",
2929 log.Fields{
2930 "port-number": action[Output].(uint32),
2931 "error": err})
2932 return uint32(0), err
2933 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302934 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2935 return intfID, nil
2936 }
2937 return uint32(0), nil
2938}
2939
2940// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302941func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302942 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2943
2944 f.lockCache.Lock()
2945 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002946 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302947 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002948 if lookupGemPort == gemPort {
2949 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2950 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2951 return
2952 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302953 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002954 f.packetInGemPort[pktInkey] = gemPort
2955
npujarec5762e2020-01-01 14:08:48 +05302956 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002957 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 +05302958 return
2959}
2960
2961// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302962func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302963
2964 f.lockCache.Lock()
2965 defer f.lockCache.Unlock()
2966 onugem := f.onuGemInfo[intfID]
2967 for idx, onu := range onugem {
2968 if onu.OnuID == onuID {
2969 for _, uni := range onu.UniPorts {
2970 if uni == portNum {
2971 log.Debugw("uni already in cache, no need to update cache and kv store",
2972 log.Fields{"uni": portNum})
2973 return
2974 }
2975 }
2976 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2977 f.onuGemInfo[intfID] = onugem
2978 }
2979 }
npujarec5762e2020-01-01 14:08:48 +05302980 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302981}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302982
npujarec5762e2020-01-01 14:08:48 +05302983func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2984 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302985 if err != nil {
2986 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2987 return
2988 }
2989 for gem, FlowIDs := range flowIDsList {
2990 gemPK := gemPortKey{intf, uint32(gem)}
2991 f.flowsUsedByGemPort[gemPK] = FlowIDs
2992 }
2993 return
2994}
Esin Karamanccb714b2019-11-29 15:02:06 +00002995
2996//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2997//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302998func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2999 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00003000 if err != nil {
3001 log.Error("Failed to get pon interface to multicast queue map")
3002 return
3003 }
3004 for intf, queueInfo := range storedMulticastQueueMap {
3005 q := queueInfoBrief{
3006 gemPortID: queueInfo[0],
3007 servicePriority: queueInfo[1],
3008 }
3009 f.interfaceToMcastQueueMap[intf] = &q
3010 }
3011}
3012
3013//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
3014//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
3015//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05303016func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
3017 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00003018 if err != nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08003019 return nil, false, NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00003020 }
3021 if exists {
3022 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3023 }
3024 return nil, exists, nil
3025}
3026
3027func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3028 groupDesc := ofp.OfpGroupDesc{
3029 Type: ofp.OfpGroupType_OFPGT_ALL,
3030 GroupId: groupID,
3031 }
3032 groupEntry := ofp.OfpGroupEntry{
3033 Desc: &groupDesc,
3034 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003035 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003036 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003037 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003038 bucket := ofp.OfpBucket{
3039 Actions: acts,
3040 }
3041 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003042 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003043 return &groupEntry
3044}