blob: dd3376014c8c25cb336e8cc1e59fe356cc12fa98 [file] [log] [blame]
manikkaraj kbf256be2019-03-25 00:13:48 +05301/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Scott Bakerdbd960e2020-02-28 08:57:51 -080017//Package core provides the utility for olt devices, flows and statistics
18package core
manikkaraj kbf256be2019-03-25 00:13:48 +053019
20import (
21 "context"
22 "crypto/md5"
Matteo Scandolo6056e822019-11-13 14:05:29 -080023 "encoding/hex"
manikkaraj kbf256be2019-03-25 00:13:48 +053024 "encoding/json"
Andrea Campanellac63bba92020-03-10 17:01:04 +010025 "errors"
manikkaraj kbf256be2019-03-25 00:13:48 +053026 "fmt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040027 "math/big"
Girish Gowdrafae935c2020-02-17 19:21:44 +053028 "strings"
William Kurkian740a09c2019-10-23 17:07:38 -040029 "sync"
Girish Gowdra3d633032019-12-10 16:37:05 +053030 "time"
Manikkaraj kb1d51442019-07-23 10:41:02 -040031
Esin Karamanccb714b2019-11-29 15:02:06 +000032 "github.com/opencord/voltha-lib-go/v3/pkg/flows"
33 "github.com/opencord/voltha-lib-go/v3/pkg/log"
34 tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
Scott Bakerdbd960e2020-02-28 08:57:51 -080035 rsrcMgr "github.com/opencord/voltha-openolt-adapter/internal/pkg/resourcemanager"
Esin Karamanccb714b2019-11-29 15:02:06 +000036 "github.com/opencord/voltha-protos/v3/go/common"
37 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
38 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
39 openoltpb2 "github.com/opencord/voltha-protos/v3/go/openolt"
40 tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
41 "github.com/opencord/voltha-protos/v3/go/voltha"
Chaitrashree G S579fe732019-08-20 20:50:47 -040042
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040043 //deepcopy "github.com/getlantern/deepcopy"
Girish Gowdra3d633032019-12-10 16:37:05 +053044 "github.com/EagleChen/mapmutex"
Thomas Lee S94109f12020-03-03 16:39:29 +053045 "github.com/opencord/voltha-openolt-adapter/internal/pkg/olterrors"
Daniele Rossi22db98e2019-07-11 11:50:00 +000046 "google.golang.org/grpc/codes"
47 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053048)
49
50const (
51 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053052
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070053 //HsiaFlow flow category
54 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053055
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070056 //EapolFlow flow category
57 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053058
Manikkaraj kb1d51442019-07-23 10:41:02 -040059 //DhcpFlow flow category
60 DhcpFlow = "DHCP_FLOW"
61
Esin Karamanccb714b2019-11-29 15:02:06 +000062 //MulticastFlow flow category
63 MulticastFlow = "MULTICAST_FLOW"
64
Esin Karamanae41e2b2019-12-17 18:13:13 +000065 //IgmpFlow flow category
66 IgmpFlow = "IGMP_FLOW"
67
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070068 //IPProtoDhcp flow category
69 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053070
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070071 //IPProtoIgmp flow category
72 IPProtoIgmp = 2
73
74 //EapEthType eapethtype value
75 EapEthType = 0x888e
76 //LldpEthType lldp ethtype value
77 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000078 //IPv4EthType IPv4 ethernet type value
79 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070080
81 //IgmpProto proto value
82 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053083
Andrea Campanella7acc0b92020-02-14 09:20:49 +010084 //ReservedVlan Transparent Vlan (Masked Vlan, VLAN_ANY in ONOS Flows)
85 ReservedVlan = 4096
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530276 return 0, olterrors.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 }
Thomas Lee S94109f12020-03-03 16:39:29 +0530369 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800370 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530401 return olterrors.NewErrNotFound("meterbands", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800402 "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})
Thomas Lee S94109f12020-03-03 16:39:29 +0530407 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800408 "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()) {
Thomas Lee S94109f12020-03-03 16:39:29 +0530666 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800667 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530713 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800714 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530749 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530753 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530758 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530763 return olterrors.NewErrNotFound("nni-interface-id",
David K. Bainbridge794735f2020-02-11 21:01:37 -0800764 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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530783 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530791 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800792 }
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530800 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800801 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530826 return olterrors.NewErrNotFound("flow", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800827 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530837 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530842 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530860 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800861 }
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530868 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530886 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800887 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530910 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800911 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530922 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530927 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530945 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800946 }
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530954 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530981 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800982 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530991 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +0530996 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301001 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001002 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301021 return olterrors.NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001022 }
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301032 return olterrors.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 {
Andrea Campanella7acc0b92020-02-14 09:20:49 +01001045 if vlanID != ReservedVlan {
1046 vid := vlanID & VlanvIDMask
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:
Thomas Lee S94109f12020-03-03 16:39:29 +05301075 return nil, olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301094 return nil, olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301312 return olterrors.NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001313 }
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301322 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001323 "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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301332 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301337 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301354 return olterrors.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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301362 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001363 }
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 {
Thomas Lee S94109f12020-03-03 16:39:29 +05301377 return nil, olterrors.NewErrNotFound("onu", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001378 "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
Andrea Campanellac63bba92020-03-10 17:01:04 +01001816func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) error {
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
Andrea Campanellac63bba92020-03-10 17:01:04 +01001829 return err
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
Andrea Campanellac63bba92020-03-10 17:01:04 +01001834 return f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001835 }
1836
manikkaraj k17652a72019-05-06 09:06:36 -04001837 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001838 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1839 if err != nil {
1840 // error if any, already logged in the called function
Andrea Campanellac63bba92020-03-10 17:01:04 +01001841 return err
manikkaraj k17652a72019-05-06 09:06:36 -04001842 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001843
David K. Bainbridge82efc492019-09-04 09:57:11 -07001844 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1845 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001846
Humera Kouser94d7a842019-08-25 19:04:32 -04001847 if ethType, ok := classifierInfo[EthType]; ok {
1848 if ethType.(uint32) == LldpEthType {
1849 log.Info("Adding LLDP flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001850 return f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001851 }
1852 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001853 if ipProto, ok := classifierInfo[IPProto]; ok {
1854 if ipProto.(uint32) == IPProtoDhcp {
1855 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301856 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001857 log.Debug("trap-dhcp-from-nni-flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001858 return f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001859 }
1860 }
1861 }
1862 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001863 if isIgmpTrapDownstreamFlow(classifierInfo) {
1864 log.Debug("trap-igmp-from-nni-flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001865 return f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001866 }
A R Karthick1f85b802019-10-11 05:06:05 +00001867
1868 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301869 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001870
Chaitrashree G S90a17952019-11-14 21:51:21 -05001871 TpID, err := getTpIDFromFlow(flow)
1872 if err != nil {
1873 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
Andrea Campanellac63bba92020-03-10 17:01:04 +01001874 return fmt.Errorf("metadata-is-not-present-invalid-flow-to-process, pon:%v, onuID:%v, uniID:%v", intfID, onuID, uniID)
Chaitrashree G S90a17952019-11-14 21:51:21 -05001875 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001876 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001877 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001878 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001879 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1880 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001881 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001882 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1883
1884 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301885
1886 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1887 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1888 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 +05301889 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301890 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301891 pendingFlowDelComplete := make(chan bool)
1892 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1893 select {
1894 case <-pendingFlowDelComplete:
1895 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301896 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301897
1898 case <-time.After(10 * time.Second):
Andrea Campanellac63bba92020-03-10 17:01:04 +01001899 log.Errorw("pending-flow-deletes-not-completed-after-timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1900 return fmt.Errorf("pending-flow-deletes-not-completed-after-timeout, pon:%v, onuID:%v, uniID:%v", intfID, onuID, uniID)
Girish Gowdra3d633032019-12-10 16:37:05 +05301901 }
1902 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01001903 return nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001904}
1905
Esin Karamanccb714b2019-11-29 15:02:06 +00001906// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001907func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001908 classifierInfo[PacketTagType] = DoubleTag
1909 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1910
npujarec5762e2020-01-01 14:08:48 +05301911 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001912 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301913 return olterrors.NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001914 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001915 //this variable acts like a switch. When it is set, multicast flows are classified by eth_dst.
1916 //otherwise, classification is based on ipv4_dst by default.
1917 //the variable can be configurable in the future; it can be read from a configuration path in the kv store.
1918 mcastFlowClassificationByEthDst := false
1919
1920 if mcastFlowClassificationByEthDst {
1921 //replace ipDst with ethDst
1922 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1923 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1924 // replace ipv4_dst classifier with eth_dst
1925 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1926 delete(classifierInfo, Ipv4Dst)
1927 classifierInfo[EthDst] = multicastMac
1928 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1929 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001930 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001931 delete(classifierInfo, EthType)
Esin Karamanccb714b2019-11-29 15:02:06 +00001932
David K. Bainbridge794735f2020-02-11 21:01:37 -08001933 onuID := NoneOnuID
1934 uniID := NoneUniID
1935 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001936
David K. Bainbridge794735f2020-02-11 21:01:37 -08001937 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1938 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301939 return olterrors.NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001940 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001941
David K. Bainbridge794735f2020-02-11 21:01:37 -08001942 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301943 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001944 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1945 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001946 }
npujarec5762e2020-01-01 14:08:48 +05301947 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001948 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301949 return olterrors.NewErrNotFound("multicast-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001950 "interface-id": networkInterfaceID,
1951 "onu-id": onuID,
1952 "uni-id": uniID,
1953 "gem-port-id": gemPortID,
1954 "cookie": flowStoreCookie},
1955 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001956 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001957 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1958 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301959 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001960 }
1961 groupID := actionInfo[GroupID].(uint32)
1962 multicastFlow := openoltpb2.Flow{
1963 FlowId: flowID,
1964 FlowType: Multicast,
1965 NetworkIntfId: int32(networkInterfaceID),
1966 GroupId: groupID,
1967 Classifier: classifierProto,
1968 Priority: int32(flow.Priority),
1969 Cookie: flow.Cookie}
1970
David K. Bainbridge794735f2020-02-11 21:01:37 -08001971 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301972 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001973 }
1974 log.Debug("multicast flow added to device successfully")
1975 //get cached group
1976 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1977 if err == nil {
1978 //calling groupAdd to set group members after multicast flow creation
Andrea Campanellac63bba92020-03-10 17:01:04 +01001979 if err = f.ModifyGroup(ctx, group); err == nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001980 //cached group can be removed now
1981 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Andrea Campanellac63bba92020-03-10 17:01:04 +01001982 } else {
1983 return olterrors.NewErrGroupOp("modify", groupID, log.Fields{"group": group}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001984 }
1985 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001986
1987 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1988 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1989 int32(onuID),
1990 int32(uniID),
1991 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301992 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001993 }
1994 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001995}
1996
1997//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301998func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001999 if _, ok := classifierInfo[InPort]; ok {
2000 return classifierInfo[InPort].(uint32), nil
2001 }
2002 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05302003 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002004 if e == nil && len(nniPorts) > 0 {
2005 return nniPorts[0], nil
2006 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302007 return 0, olterrors.NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002008}
2009
2010// AddGroup add or update the group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002011func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002012 log.Infow("add-group", log.Fields{"group": group})
2013 if group == nil {
2014 log.Warn("skipping nil group")
Andrea Campanellac63bba92020-03-10 17:01:04 +01002015 return errors.New("group is nil")
Esin Karamanccb714b2019-11-29 15:02:06 +00002016 }
2017
2018 groupToOlt := openoltpb2.Group{
2019 GroupId: group.Desc.GroupId,
2020 Command: openoltpb2.Group_SET_MEMBERS,
2021 Action: f.buildGroupAction(),
2022 }
2023
2024 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302025 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002026 if err != nil {
2027 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
Andrea Campanellac63bba92020-03-10 17:01:04 +01002028 return fmt.Errorf("add-group operation failed, err %v, groupToOlt %v", err, groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002029 }
2030 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302031 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002032 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
Andrea Campanellac63bba92020-03-10 17:01:04 +01002033 return fmt.Errorf("group cannot be stored in KV store, groupId %v, err %v", group.Desc.GroupId, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002034 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002035 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2036 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002037}
2038
2039//buildGroupAction creates and returns a group action
2040func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2041 var actionCmd openoltpb2.ActionCmd
2042 var action openoltpb2.Action
2043 action.Cmd = &actionCmd
2044 //pop outer vlan
2045 action.Cmd.RemoveOuterTag = true
2046 return &action
2047}
2048
2049// ModifyGroup updates the group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002050func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002051 log.Infow("modify-group", log.Fields{"group": group})
2052 if group == nil || group.Desc == nil {
2053 log.Warn("cannot modify group; group is nil")
Andrea Campanellac63bba92020-03-10 17:01:04 +01002054 return errors.New("cannot modify group; group is nil")
Esin Karamanccb714b2019-11-29 15:02:06 +00002055 }
2056
Andrea Campanellac63bba92020-03-10 17:01:04 +01002057 newGroup := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
Esin Karamanccb714b2019-11-29 15:02:06 +00002058 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302059 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002060
2061 if err != nil {
2062 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2063 log.Fields{"groupId": group.Desc.GroupId, "err": err})
Andrea Campanellac63bba92020-03-10 17:01:04 +01002064 return fmt.Errorf("failed to retrieve the group from the store. Cannot modify group. groupId:%v, err:%v", group.Desc.GroupId, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002065 }
2066
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002067 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002068 if groupExists {
2069 // group already exists
2070 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002071 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002072 } else {
2073 current = f.buildGroup(group.Desc.GroupId, nil)
2074 }
2075
Andrea Campanellac63bba92020-03-10 17:01:04 +01002076 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": newGroup})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002077 // get members to be added
Andrea Campanellac63bba92020-03-10 17:01:04 +01002078 membersToBeAdded := f.findDiff(current, newGroup)
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002079 // get members to be removed
Andrea Campanellac63bba92020-03-10 17:01:04 +01002080 membersToBeRemoved := f.findDiff(newGroup, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002081
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002082 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2083 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002084
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002085 groupToOlt := openoltpb2.Group{
2086 GroupId: group.Desc.GroupId,
2087 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002088 var errAdd, errRemoved error
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002089 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2090 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2091 groupToOlt.Members = membersToBeAdded
2092 //execute addMembers
Andrea Campanellac63bba92020-03-10 17:01:04 +01002093 errAdd = f.callGroupAddRemove(&groupToOlt)
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002094 }
2095 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2096 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2097 groupToOlt.Members = membersToBeRemoved
2098 //execute removeMembers
Andrea Campanellac63bba92020-03-10 17:01:04 +01002099 errRemoved = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002100 }
2101
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002102 //save the modified group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002103 if errAdd == nil && errRemoved == nil {
npujarec5762e2020-01-01 14:08:48 +05302104 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Andrea Campanellac63bba92020-03-10 17:01:04 +01002105 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId, "error": err})
2106 return fmt.Errorf("failed to save the group into kv store. groupId:%v, err:%v", group.Desc.GroupId, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002107 }
2108 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002109 } else {
2110 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2111 log.Fields{"group": group})
Andrea Campanellac63bba92020-03-10 17:01:04 +01002112 if errAdd != nil {
2113 return errAdd
2114 }
2115 return errRemoved
Esin Karamanccb714b2019-11-29 15:02:06 +00002116 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002117 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002118}
2119
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002120//callGroupAddRemove performs add/remove buckets operation for the indicated group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002121func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) error {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002122 if err := f.performGroupOperation(group); err != nil {
2123 st, _ := status.FromError(err)
2124 //ignore already exists error code
2125 if st.Code() != codes.AlreadyExists {
Andrea Campanellac63bba92020-03-10 17:01:04 +01002126 return olterrors.NewErrGroupOp("groupAddRemove", group.GroupId, log.Fields{"status": st}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002127 }
2128 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002129 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002130}
2131
2132//findDiff compares group members and finds members which only exists in groups2
2133func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2134 var members []*openoltpb2.GroupMember
2135 for _, bucket := range group2.Members {
2136 if !f.contains(group1.Members, bucket) {
2137 // bucket does not exist and must be added
2138 members = append(members, bucket)
2139 }
2140 }
2141 return members
2142}
2143
2144//contains returns true if the members list contains the given member; false otherwise
2145func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2146 for _, groupMember := range members {
2147 if groupMember.InterfaceId == member.InterfaceId {
2148 return true
2149 }
2150 }
2151 return false
2152}
2153
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002154//performGroupOperation call performGroupOperation operation of openolt proto
2155func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002156 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2157 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2158 if err != nil {
2159 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2160 }
2161 return err
2162}
2163
2164//buildGroup build openoltpb2.Group from given group id and bucket list
2165func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2166 group := openoltpb2.Group{
2167 GroupId: groupID}
2168 // create members of the group
2169 if buckets != nil {
2170 for _, ofBucket := range buckets {
2171 member := f.buildMember(ofBucket)
2172 if member != nil && !f.contains(group.Members, member) {
2173 group.Members = append(group.Members, member)
2174 }
2175 }
2176 }
2177 return &group
2178}
2179
2180//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2181func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2182 var outPort uint32
2183 outPortFound := false
2184 for _, ofAction := range ofBucket.Actions {
2185 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2186 outPort = ofAction.GetOutput().Port
2187 outPortFound = true
2188 }
2189 }
2190
2191 if !outPortFound {
2192 log.Debugw("bucket skipped since no out port found in it",
2193 log.Fields{"ofBucket": ofBucket})
2194 return nil
2195 }
2196 interfaceID := IntfIDFromUniPortNum(outPort)
2197 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2198 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2199 member := openoltpb2.GroupMember{
2200 InterfaceId: interfaceID,
2201 InterfaceType: openoltpb2.GroupMember_PON,
2202 GemPortId: groupInfo.gemPortID,
2203 Priority: groupInfo.servicePriority,
2204 }
2205 //add member to the group
2206 return &member
2207 }
2208 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2209 log.Fields{"ofBucket": ofBucket})
2210 return nil
2211}
2212
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002213//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002214func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002215
2216 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302217 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002218 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302219 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302220 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302221 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002222
Manikkaraj kb1d51442019-07-23 10:41:02 -04002223 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002224 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002225 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2226 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2227 tpDownloadMsg,
2228 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2229 f.deviceHandler.deviceType,
2230 onuDevice.Type,
2231 onuDevice.Id,
2232 onuDevice.ProxyAddress.DeviceId, "")
2233 if sendErr != nil {
2234 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2235 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2236 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2237 return sendErr
2238 }
2239 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302240 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302241}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002242
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302243//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302244func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302245
2246 f.lockCache.Lock()
2247 defer f.lockCache.Unlock()
2248 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2249 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002250 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2251 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302252 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2253 return
2254 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002255 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2256}
2257
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302258//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302259func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302260 f.lockCache.Lock()
2261 defer f.lockCache.Unlock()
2262 onugem := f.onuGemInfo[intfID]
2263 // update the gem to the local cache as well as to kv strore
2264 for idx, onu := range onugem {
2265 if onu.OnuID == onuID {
2266 // check if gem already exists , else update the cache and kvstore
2267 for _, gem := range onu.GemPorts {
2268 if gem == gemPort {
2269 log.Debugw("Gem already in cache, no need to update cache and kv store",
2270 log.Fields{"gem": gemPort})
2271 return
2272 }
2273 }
2274 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2275 f.onuGemInfo[intfID] = onugem
2276 }
2277 }
npujarec5762e2020-01-01 14:08:48 +05302278 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302279 if err != nil {
2280 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002281 return
2282 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002283}
2284
2285// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002286
2287//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2288func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302289
2290 f.lockCache.Lock()
2291 defer f.lockCache.Unlock()
2292
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002293 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 +05302294 // get onuid from the onugem info cache
2295 onugem := f.onuGemInfo[intfID]
2296 for _, onu := range onugem {
2297 for _, gem := range onu.GemPorts {
2298 if gem == gemPortID {
2299 return onu.OnuID, nil
2300 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002301 }
2302 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302303 return uint32(0), olterrors.NewErrNotFound("onu-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002304 "serial-number": serialNumber,
2305 "interface-id": intfID,
2306 "gem-port-id": gemPortID},
2307 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002308}
2309
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002310//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302311func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002312 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002313 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002314 var err error
2315
2316 if packetIn.IntfType == "pon" {
2317 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002318 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002319 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2320 return logicalPortNum, err
2321 }
2322 if packetIn.PortNo != 0 {
2323 logicalPortNum = packetIn.PortNo
2324 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002325 uniID := uint32(0) // FIXME - multi-uni support
2326 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002327 }
2328 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302329 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002330 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002331 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002332 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002333 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2334 "logicalPortNum": logicalPortNum,
2335 "IntfType": packetIn.IntfType,
2336 "packet": hex.EncodeToString(packetIn.Pkt),
2337 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002338 return logicalPortNum, nil
2339}
2340
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002341//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302342func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002343 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002344 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302345
2346 f.lockCache.Lock()
2347 defer f.lockCache.Unlock()
2348 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2349
2350 gemPortID, ok := f.packetInGemPort[pktInkey]
2351 if ok {
2352 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2353 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002354 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302355 //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 +05302356 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302357 if err == nil {
2358 if gemPortID != 0 {
2359 f.packetInGemPort[pktInkey] = gemPortID
2360 log.Debugw("Found gem port from kv store and updating cache with gemport",
2361 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2362 return gemPortID, nil
2363 }
2364 }
2365 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2366 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002367}
2368
npujarec5762e2020-01-01 14:08:48 +05302369func installFlowOnAllGemports(ctx context.Context,
2370 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002371 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002372 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302373 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302374 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302375 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302376 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002377 args map[string]uint32,
2378 classifier map[string]interface{}, action map[string]interface{},
2379 logicalFlow *ofp.OfpFlowStats,
2380 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302381 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002382 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002383 vlanID ...uint32) {
2384 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302385
2386 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2387 var gemPortID uint32
2388 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2389 // We need to trim prefix "0b", before further processing
2390 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2391 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2392 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2393 // If a particular character in the string is set to '1', identify the index of this character from
2394 // the LSB position which marks the PCP bit consumed by the given gem port.
2395 // This PCP bit now becomes a classifier in the flow.
2396 if pbitSet == BinaryBit1 {
2397 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2398 gemPortID = gemPortAttribute.GemportID
2399 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2400 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2401 } else if FlowType == EapolFlow {
2402 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2403 } else {
2404 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2405 return
2406 }
2407 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002408 }
2409 }
2410}
2411
David K. Bainbridge794735f2020-02-11 21:01:37 -08002412func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002413 log.Debug("Adding trap-dhcp-of-nni-flow")
2414 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002415 classifier[PacketTagType] = DoubleTag
2416 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002417 /* We manage flowId resource pool on per PON port basis.
2418 Since this situation is tricky, as a hack, we pass the NNI port
2419 index (network_intf_id) as PON port Index for the flowId resource
2420 pool. Also, there is no ONU Id available for trapping DHCP packets
2421 on NNI port, use onu_id as -1 (invalid)
2422 ****************** CAVEAT *******************
2423 This logic works if the NNI Port Id falls within the same valid
2424 range of PON Port Ids. If this doesn't work for some OLT Vendor
2425 we need to have a re-look at this.
2426 *********************************************
2427 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002428 onuID := -1
2429 uniID := -1
2430 gemPortID := -1
2431 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002432 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302433 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302434 return olterrors.NewErrNotFound("nni-intreface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002435 "classifier": classifier,
2436 "action": action},
2437 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302438 }
2439
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002440 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302441 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002442 log.Debug("Flow-exists-not-re-adding")
2443 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002444 }
npujarec5762e2020-01-01 14:08:48 +05302445 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002446 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302447 return olterrors.NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002448 "interface-id": networkInterfaceID,
2449 "onu-id": onuID,
2450 "uni-id": uniID,
2451 "gem-port-id": gemPortID,
2452 "cookie": flowStoreCookie},
2453 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002454 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002455 classifierProto, err := makeOpenOltClassifierField(classifier)
2456 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302457 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002458 }
2459 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002460 actionProto, err := makeOpenOltActionField(action)
2461 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302462 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002463 }
2464 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002465 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2466 OnuId: int32(onuID), // OnuId not required
2467 UniId: int32(uniID), // UniId not used
2468 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002469 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002470 AllocId: int32(allocID), // AllocId not used
2471 NetworkIntfId: int32(networkInterfaceID),
2472 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002473 Classifier: classifierProto,
2474 Action: actionProto,
2475 Priority: int32(logicalFlow.Priority),
2476 Cookie: logicalFlow.Cookie,
2477 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002478 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302479 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002480 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002481 log.Debug("DHCP trap on NNI flow added to device successfully")
2482 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2483 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2484 int32(onuID),
2485 int32(uniID),
2486 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302487 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08002488 }
2489 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002490}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002491
Esin Karamanae41e2b2019-12-17 18:13:13 +00002492//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2493func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2494 var packetType string
2495 ovid, ivid := false, false
2496 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2497 vid := vlanID & VlanvIDMask
2498 if vid != ReservedVlan {
2499 ovid = true
2500 }
2501 }
2502 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2503 vid := uint32(metadata)
2504 if vid != ReservedVlan {
2505 ivid = true
2506 }
2507 }
2508 if ovid && ivid {
2509 packetType = DoubleTag
2510 } else if !ovid && !ivid {
2511 packetType = Untagged
2512 } else {
2513 packetType = SingleTag
2514 }
2515 return packetType
2516}
2517
2518//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002519func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002520 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2521 action := make(map[string]interface{})
2522 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2523 action[TrapToHost] = true
2524 /* We manage flowId resource pool on per PON port basis.
2525 Since this situation is tricky, as a hack, we pass the NNI port
2526 index (network_intf_id) as PON port Index for the flowId resource
2527 pool. Also, there is no ONU Id available for trapping packets
2528 on NNI port, use onu_id as -1 (invalid)
2529 ****************** CAVEAT *******************
2530 This logic works if the NNI Port Id falls within the same valid
2531 range of PON Port Ids. If this doesn't work for some OLT Vendor
2532 we need to have a re-look at this.
2533 *********************************************
2534 */
2535 onuID := -1
2536 uniID := -1
2537 gemPortID := -1
2538 allocID := -1
2539 networkInterfaceID, err := getNniIntfID(classifier, action)
2540 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302541 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002542 "classifier": classifier,
2543 "action": action},
2544 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002545 }
2546 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302547 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002548 log.Debug("igmp-flow-exists-not-re-adding")
2549 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002550 }
npujarec5762e2020-01-01 14:08:48 +05302551 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002552 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302553 return olterrors.NewErrNotFound("igmp-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002554 "interface-id": networkInterfaceID,
2555 "onu-id": onuID,
2556 "uni-id": uniID,
2557 "gem-port-id": gemPortID,
2558 "cookie": flowStoreCookie},
2559 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002560 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002561 classifierProto, err := makeOpenOltClassifierField(classifier)
2562 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302563 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002564 }
2565 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002566 actionProto, err := makeOpenOltActionField(action)
2567 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302568 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002569 }
2570 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2571 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2572 OnuId: int32(onuID), // OnuId not required
2573 UniId: int32(uniID), // UniId not used
2574 FlowId: flowID,
2575 FlowType: Downstream,
2576 AllocId: int32(allocID), // AllocId not used
2577 NetworkIntfId: int32(networkInterfaceID),
2578 GemportId: int32(gemPortID), // GemportId not used
2579 Classifier: classifierProto,
2580 Action: actionProto,
2581 Priority: int32(logicalFlow.Priority),
2582 Cookie: logicalFlow.Cookie,
2583 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002584 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302585 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002586 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002587 log.Debug("IGMP Trap on NNI flow added to device successfully")
2588 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2589 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2590 int32(onuID),
2591 int32(uniID),
2592 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302593 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08002594 }
2595 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002596}
2597
salmansiddiqui7ac62132019-08-22 03:58:50 +00002598func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2599 if MeterID == 0 { // This should never happen
Thomas Lee S94109f12020-03-03 16:39:29 +05302600 return "", olterrors.NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002601 }
2602 if Dir == tp_pb.Direction_UPSTREAM {
2603 return "upstream", nil
2604 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2605 return "downstream", nil
2606 }
2607 return "", nil
2608}
2609
npujarec5762e2020-01-01 14:08:48 +05302610func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002611 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2612 TpID uint32, uni string) {
2613 var gemPort uint32
2614 intfID := args[IntfID]
2615 onuID := args[OnuID]
2616 uniID := args[UniID]
2617 portNo := args[PortNo]
2618 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002619 if ipProto, ok := classifierInfo[IPProto]; ok {
2620 if ipProto.(uint32) == IPProtoDhcp {
2621 log.Info("Adding DHCP flow")
2622 if pcp, ok := classifierInfo[VlanPcp]; ok {
2623 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2624 tp_pb.Direction_UPSTREAM,
2625 pcp.(uint32))
2626 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302627 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002628 } else {
2629 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302630 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002631 }
2632
2633 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002634 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2635 if pcp, ok := classifierInfo[VlanPcp]; ok {
2636 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2637 tp_pb.Direction_UPSTREAM,
2638 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302639 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002640 } else {
2641 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302642 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002643 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002644 } else {
2645 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2646 return
2647 }
2648 } else if ethType, ok := classifierInfo[EthType]; ok {
2649 if ethType.(uint32) == EapEthType {
2650 log.Info("Adding EAPOL flow")
2651 var vlanID uint32
2652 if val, ok := classifierInfo[VlanVid]; ok {
2653 vlanID = (val.(uint32)) & VlanvIDMask
2654 } else {
2655 vlanID = DefaultMgmtVlan
2656 }
2657 if pcp, ok := classifierInfo[VlanPcp]; ok {
2658 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2659 tp_pb.Direction_UPSTREAM,
2660 pcp.(uint32))
2661
Girish Gowdrafae935c2020-02-17 19:21:44 +05302662 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002663 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302664 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002665 }
2666 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002667 } else if _, ok := actionInfo[PushVlan]; ok {
2668 log.Info("Adding upstream data rule")
2669 if pcp, ok := classifierInfo[VlanPcp]; ok {
2670 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2671 tp_pb.Direction_UPSTREAM,
2672 pcp.(uint32))
2673 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302674 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002675 } else {
2676 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302677 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002678 }
2679 } else if _, ok := actionInfo[PopVlan]; ok {
2680 log.Info("Adding Downstream data rule")
2681 if pcp, ok := classifierInfo[VlanPcp]; ok {
2682 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002683 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002684 pcp.(uint32))
2685 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302686 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002687 } else {
2688 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302689 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002690 }
2691 } else {
2692 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2693 return
2694 }
2695 // Send Techprofile download event to child device in go routine as it takes time
2696 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2697}
2698
Gamze Abakafee36392019-10-03 11:17:24 +00002699func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2700 flowIDList := f.flowsUsedByGemPort[gemPK]
2701 if len(flowIDList) > 1 {
2702 return true
2703 }
2704 return false
2705}
2706
npujarec5762e2020-01-01 14:08:48 +05302707func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2708 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002709 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2710 for _, currentGemPort := range currentGemPorts {
2711 for _, tpGemPort := range tpGemPorts {
2712 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2713 return true, currentGemPort
2714 }
2715 }
2716 }
Girish Gowdra54934262019-11-13 14:19:55 +05302717 if tpInst.InstanceCtrl.Onu == "single-instance" {
2718 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302719 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2720 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302721
2722 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2723 // still be used on other uni ports.
2724 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2725 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302726 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302727 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302728 for i := 0; i < len(tpInstances); i++ {
2729 tpI := tpInstances[i]
2730 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302731 for _, tpGemPort := range tpGemPorts {
2732 if tpGemPort.GemportID != gemPortID {
2733 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2734 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302735 }
2736 }
2737 }
2738 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302739 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002740 return false, 0
2741}
2742
salmansiddiqui7ac62132019-08-22 03:58:50 +00002743func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002744 for _, field := range flows.GetOfbFields(flow) {
2745 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002746 classifierInfo[EthType] = field.GetEthType()
2747 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002748 } else if field.Type == flows.ETH_DST {
2749 classifierInfo[EthDst] = field.GetEthDst()
2750 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002751 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002752 classifierInfo[IPProto] = field.GetIpProto()
2753 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002754 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002755 classifierInfo[InPort] = field.GetPort()
2756 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002757 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302758 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002759 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002760 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002761 classifierInfo[VlanPcp] = field.GetVlanPcp()
2762 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002763 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002764 classifierInfo[UDPDst] = field.GetUdpDst()
2765 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002766 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002767 classifierInfo[UDPSrc] = field.GetUdpSrc()
2768 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002769 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002770 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2771 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002772 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002773 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2774 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002775 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002776 classifierInfo[Metadata] = field.GetTableMetadata()
2777 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002778 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002779 classifierInfo[TunnelID] = field.GetTunnelId()
2780 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2781 } else {
2782 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2783 return
2784 }
2785 }
2786}
2787
2788func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002789 for _, action := range flows.GetActions(flow) {
2790 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002791 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002792 actionInfo[Output] = out.GetPort()
2793 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002794 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302795 return olterrors.NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002796 }
Scott Baker355d1742019-10-24 10:57:52 -07002797 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002798 actionInfo[PopVlan] = true
2799 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002800 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002801 if out := action.GetPush(); out != nil {
2802 if tpid := out.GetEthertype(); tpid != 0x8100 {
2803 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2804 } else {
2805 actionInfo[PushVlan] = true
2806 actionInfo[TPID] = tpid
2807 log.Debugw("action-type-push-vlan",
2808 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2809 }
2810 }
Scott Baker355d1742019-10-24 10:57:52 -07002811 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002812 if out := action.GetSetField(); out != nil {
2813 if field := out.GetField(); field != nil {
2814 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
Thomas Lee S94109f12020-03-03 16:39:29 +05302815 return olterrors.NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002816 }
2817 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002818 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002819 }
2820 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002821 } else if action.Type == flows.GROUP {
2822 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002823 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302824 return olterrors.NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002825 }
2826 }
2827 return nil
2828}
2829
Esin Karamanccb714b2019-11-29 15:02:06 +00002830func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2831 if ofbField := field.GetOfbField(); ofbField != nil {
2832 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2833 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2834 actionInfo[VlanVid] = vlan & 0xfff
2835 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2836 } else {
2837 log.Error("No Invalid vlan id in set vlan-vid action")
2838 }
2839 } else {
2840 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2841 }
2842 }
2843}
2844
2845func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2846 if action.GetGroup() == nil {
2847 log.Warn("No group entry found in the group action")
2848 } else {
2849 actionInfo[GroupID] = action.GetGroup().GroupId
2850 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2851 }
2852}
2853
salmansiddiqui7ac62132019-08-22 03:58:50 +00002854func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002855 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002856 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2857 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2858 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002859 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002860 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002861 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 +00002862 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302863 return olterrors.NewErrNotFound("child-in-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002864 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2865 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002866 }
2867 }
2868 } else {
2869 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2870 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002871 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002872 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002873 actionInfo[Output] = uniPort
2874 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 +00002875 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302876 return olterrors.NewErrNotFound("out-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002877 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2878 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002879 }
2880 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2881 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002882 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002883 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002884 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2885 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002886 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302887 return olterrors.NewErrNotFound("nni-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002888 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2889 "in-port": classifierInfo[InPort].(uint32),
2890 "out-port": actionInfo[Output].(uint32),
2891 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002892 }
2893 }
2894 }
2895 return nil
2896}
Gamze Abakafee36392019-10-03 11:17:24 +00002897
Chaitrashree G S90a17952019-11-14 21:51:21 -05002898func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002899 /* Metadata 8 bytes:
2900 Most Significant 2 Bytes = Inner VLAN
2901 Next 2 Bytes = Tech Profile ID(TPID)
2902 Least Significant 4 Bytes = Port ID
2903 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2904 subscriber related flows.
2905 */
2906 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2907 if metadata == 0 {
Thomas Lee S94109f12020-03-03 16:39:29 +05302908 return 0, olterrors.NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002909 }
2910 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002911 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002912}
2913
2914func appendUnique(slice []uint32, item uint32) []uint32 {
2915 for _, sliceElement := range slice {
2916 if sliceElement == item {
2917 return slice
2918 }
2919 }
2920 return append(slice, item)
2921}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302922
2923// getNniIntfID gets nni intf id from the flow classifier/action
2924func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2925
2926 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2927 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002928 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2929 if err != nil {
2930 log.Debugw("invalid-action-port-number",
2931 log.Fields{
2932 "port-number": action[Output].(uint32),
2933 "error": err})
2934 return uint32(0), err
2935 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302936 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2937 return intfID, nil
2938 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002939 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2940 if err != nil {
2941 log.Debugw("invalid-classifier-port-number",
2942 log.Fields{
2943 "port-number": action[Output].(uint32),
2944 "error": err})
2945 return uint32(0), err
2946 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302947 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2948 return intfID, nil
2949 }
2950 return uint32(0), nil
2951}
2952
2953// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302954func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302955 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2956
2957 f.lockCache.Lock()
2958 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002959 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302960 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002961 if lookupGemPort == gemPort {
2962 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2963 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2964 return
2965 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302966 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002967 f.packetInGemPort[pktInkey] = gemPort
2968
npujarec5762e2020-01-01 14:08:48 +05302969 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002970 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 +05302971 return
2972}
2973
2974// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302975func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302976
2977 f.lockCache.Lock()
2978 defer f.lockCache.Unlock()
2979 onugem := f.onuGemInfo[intfID]
2980 for idx, onu := range onugem {
2981 if onu.OnuID == onuID {
2982 for _, uni := range onu.UniPorts {
2983 if uni == portNum {
2984 log.Debugw("uni already in cache, no need to update cache and kv store",
2985 log.Fields{"uni": portNum})
2986 return
2987 }
2988 }
2989 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2990 f.onuGemInfo[intfID] = onugem
2991 }
2992 }
npujarec5762e2020-01-01 14:08:48 +05302993 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302994}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302995
npujarec5762e2020-01-01 14:08:48 +05302996func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2997 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302998 if err != nil {
2999 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
3000 return
3001 }
3002 for gem, FlowIDs := range flowIDsList {
3003 gemPK := gemPortKey{intf, uint32(gem)}
3004 f.flowsUsedByGemPort[gemPK] = FlowIDs
3005 }
3006 return
3007}
Esin Karamanccb714b2019-11-29 15:02:06 +00003008
3009//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
3010//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05303011func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
3012 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00003013 if err != nil {
3014 log.Error("Failed to get pon interface to multicast queue map")
3015 return
3016 }
3017 for intf, queueInfo := range storedMulticastQueueMap {
3018 q := queueInfoBrief{
3019 gemPortID: queueInfo[0],
3020 servicePriority: queueInfo[1],
3021 }
3022 f.interfaceToMcastQueueMap[intf] = &q
3023 }
3024}
3025
3026//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
3027//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
3028//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05303029func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
3030 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00003031 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05303032 return nil, false, olterrors.NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00003033 }
3034 if exists {
3035 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3036 }
3037 return nil, exists, nil
3038}
3039
3040func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3041 groupDesc := ofp.OfpGroupDesc{
3042 Type: ofp.OfpGroupType_OFPGT_ALL,
3043 GroupId: groupID,
3044 }
3045 groupEntry := ofp.OfpGroupEntry{
3046 Desc: &groupDesc,
3047 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003048 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003049 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003050 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003051 bucket := ofp.OfpBucket{
3052 Actions: acts,
3053 }
3054 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003055 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003056 return &groupEntry
3057}