blob: 0ca3a7f4f2e6a097cfce6823eb94d7643833c552 [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"
Girish Gowdracefae192020-03-19 18:14:10 -070025 "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 {
Girish Kumarf26e4882020-03-05 06:49:10 +0000239 log.Errorw("Error while populating tech profile mgr", log.Fields{"error": err})
manikkaraj kbf256be2019-03-25 00:13:48 +0530240 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 {
Girish Kumarf26e4882020-03-05 06:49:10 +0000361 return olterrors.NewErrNotFound("meter", log.Fields{"intfId": sq.intfID, "onuId": sq.onuID, "uniId": sq.uniID}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400362 }
Girish Kumarf26e4882020-03-05 06:49:10 +0000363
Manikkaraj kb1d51442019-07-23 10:41:02 -0400364 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,
Girish Kumarf26e4882020-03-05 06:49:10 +0000372 "meter-id-in-flow": sq.meterID}, nil)
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 {
Girish Kumarf26e4882020-03-05 06:49:10 +0000384 return olterrors.NewErrNotFound("scheduler-config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "tpInst": sq.tpInst}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000385 }
386
Manikkaraj kb1d51442019-07-23 10:41:02 -0400387 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000388 if sq.flowMetadata != nil {
389 for _, meter := range sq.flowMetadata.Meters {
390 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400391 meterConfig = meter
392 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
393 break
394 }
395 }
396 } else {
397 log.Error("Flow-metadata-is-not-present-in-flow")
398 }
399 if meterConfig == nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530400 return olterrors.NewErrNotFound("meterbands", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800401 "reason": "Could-not-get-meterbands-from-flowMetadata",
402 "flow-metadata": sq.flowMetadata,
Girish Kumarf26e4882020-03-05 06:49:10 +0000403 "meter-id": sq.meterID}, nil)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400404 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000405 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
Thomas Lee S94109f12020-03-03 16:39:29 +0530406 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800407 "reason": "Invalid-number-of-bands-in-meter",
408 "meterband-count": len(meterConfig.Bands),
409 "metabands": meterConfig.Bands,
Girish Kumarf26e4882020-03-05 06:49:10 +0000410 "meter-id": sq.meterID}, nil)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400411 }
412 cir := meterConfig.Bands[0].Rate
413 cbs := meterConfig.Bands[0].BurstSize
414 eir := meterConfig.Bands[1].Rate
415 ebs := meterConfig.Bands[1].BurstSize
416 pir := cir + eir
417 pbs := cbs + ebs
418 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
419
Gamze Abakafee36392019-10-03 11:17:24 +0000420 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400421
npujarec5762e2020-01-01 14:08:48 +0530422 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000423 return olterrors.NewErrAdapter("failure-pushing-traffic-scheduler-and-queues-to-device", log.Fields{"intfID": sq.intfID, "direction": sq.direction}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400424 }
425
salmansiddiqui7ac62132019-08-22 03:58:50 +0000426 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400427 * store the meter id on the KV store, for further reference.
428 */
npujarec5762e2020-01-01 14:08:48 +0530429 if err := f.resourceMgr.UpdateMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID, meterConfig); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000430 return olterrors.NewErrAdapter("failed-updating-meter-id", log.Fields{"onu-id": sq.onuID, "meter-id": sq.meterID}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400431 }
432 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
433 "Meter": meterConfig})
434 return nil
435}
436
npujarec5762e2020-01-01 14:08:48 +0530437func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000438
439 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
440
441 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000442 return olterrors.NewErrAdapter("unable-to-construct-traffic-queue-configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000443 }
444
445 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530446 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000447 IntfId: sq.intfID, OnuId: sq.onuID,
448 UniId: sq.uniID, PortNo: sq.uniPort,
449 TrafficScheds: TrafficSched}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000450 return olterrors.NewErrAdapter("failed-to-create-traffic-schedulers-in-device", log.Fields{"TrafficScheds": TrafficSched}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000451 }
452
453 // On receiving the CreateTrafficQueues request, the driver should create corresponding
454 // downstream queues.
455 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530456 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000457 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
458 UniId: sq.uniID, PortNo: sq.uniPort,
459 TrafficQueues: trafficQueues}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000460 return olterrors.NewErrAdapter("failed-to-create-traffic-queues-in-device", log.Fields{"TrafficQueues": trafficQueues}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000461 }
462
Esin Karamanccb714b2019-11-29 15:02:06 +0000463 if sq.direction == tp_pb.Direction_DOWNSTREAM {
464 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
465 if len(multicastTrafficQueues) > 0 {
466 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
467 //assumed that there is only one queue per PON for the multicast service
468 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
469 //just put it in interfaceToMcastQueueMap to use for building group members
470 multicastQueuePerPonPort := multicastTrafficQueues[0]
471 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
472 gemPortID: multicastQueuePerPonPort.GemportId,
473 servicePriority: multicastQueuePerPonPort.Priority,
474 }
475 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530476 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000477 multicastQueuePerPonPort.GemportId,
478 multicastQueuePerPonPort.Priority)
479 }
480 }
481 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000482 return nil
483}
484
salmansiddiqui7ac62132019-08-22 03:58:50 +0000485// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530486func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400487
488 var Direction string
489 var SchedCfg *tp_pb.SchedulerConfig
490 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000491 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
492 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
493 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000494 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400495 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000496 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000497 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400498 Direction = "downstream"
499 }
500
Girish Kumar8f73fe02019-12-09 13:19:37 +0000501 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000502 return olterrors.NewErrNotFound("scheduler-config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000503 }
504
npujarec5762e2020-01-01 14:08:48 +0530505 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400506 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000507 return olterrors.NewErrNotFound("meter", log.Fields{"onuID": sq.onuID}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400508 }
509 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000510 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 -0400511 return nil
512 }
513 cir := KVStoreMeter.Bands[0].Rate
514 cbs := KVStoreMeter.Bands[0].BurstSize
515 eir := KVStoreMeter.Bands[1].Rate
516 ebs := KVStoreMeter.Bands[1].BurstSize
517 pir := cir + eir
518 pbs := cbs + ebs
519
520 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
521
Gamze Abakafee36392019-10-03 11:17:24 +0000522 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000523
524 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
525 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000526 return olterrors.NewErrAdapter("unable-to-construct-traffic-queue-configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000527 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400528
npujarec5762e2020-01-01 14:08:48 +0530529 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000530 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
531 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400532 TrafficQueues: TrafficQueues}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000533 return olterrors.NewErrAdapter("unable-to-remove-traffic-queues-from-device",
534 log.Fields{"intfID": sq.intfID, "TrafficQueues": TrafficQueues}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400535 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000536 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530537 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000538 IntfId: sq.intfID, OnuId: sq.onuID,
539 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400540 TrafficScheds: TrafficSched}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000541 return olterrors.NewErrAdapter("unable-to-remove-traffic-schedulers-from-device",
542 log.Fields{"intfID": sq.intfID, "TrafficSchedulers": TrafficSched}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400543 }
544
salmansiddiqui7ac62132019-08-22 03:58:50 +0000545 log.Debug("Removed traffic schedulers successfully")
546
547 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400548 * delete the meter id on the KV store.
549 */
npujarec5762e2020-01-01 14:08:48 +0530550 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400551 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000552 return olterrors.NewErrAdapter("unable-to-remove-meter", log.Fields{"onu": sq.onuID, "meter": KVStoreMeter.MeterId}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400553 }
554 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
555 return err
556}
557
Gamze Abakafee36392019-10-03 11:17:24 +0000558// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530559func (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 +0000560 var allocIDs []uint32
561 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530562 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530563 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000564 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000565
npujarec5762e2020-01-01 14:08:48 +0530566 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
567 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400568
569 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530570
571 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
572
Manikkaraj kb1d51442019-07-23 10:41:02 -0400573 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530574 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000575 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530576 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530577 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000578 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530579 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000580 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000581 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530582 }
npujarec5762e2020-01-01 14:08:48 +0530583 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530584 } else {
585 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530586 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530587 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400588 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000589 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
590 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530591 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400592 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000593 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400594 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530595 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400596 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000597 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
598 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530599 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400600 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000601 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400602 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530603 }
Gamze Abakafee36392019-10-03 11:17:24 +0000604
605 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000606 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000607 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400608 }
Gamze Abakafee36392019-10-03 11:17:24 +0000609
Girish Gowdra3d633032019-12-10 16:37:05 +0530610 if tpInstanceExists {
611 return allocID, gemPortIDs, techProfileInstance
612 }
613
614 allocIDs = appendUnique(allocIDs, allocID)
615 for _, gemPortID := range gemPortIDs {
616 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
617 }
618
Gamze Abakafee36392019-10-03 11:17:24 +0000619 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530620 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530621 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000622 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530623}
624
npujarec5762e2020-01-01 14:08:48 +0530625func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530626
627 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700628 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530629 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530630 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530631 log.Error("Errow while uploading allocID to KV store")
632 }
npujarec5762e2020-01-01 14:08:48 +0530633 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530634 log.Error("Errow while uploading GEMports to KV store")
635 }
npujarec5762e2020-01-01 14:08:48 +0530636 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530637 log.Error("Errow while uploading gemtopon map to KV store")
638 }
639 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400640 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530641 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400642 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530643}
644
645func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000646 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530647 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000648 for _, intfID := range techRange.IntfIds {
649 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400650 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000651 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530652 }
653 }
654 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400655 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
Thomas Lee S94109f12020-03-03 16:39:29 +0530656 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800657 "reason": "TP count does not match number of PON ports",
658 "tech-profile-count": tpCount,
Girish Kumarf26e4882020-03-05 06:49:10 +0000659 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil)
manikkaraj kbf256be2019-03-25 00:13:48 +0530660 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400661 log.Infow("Populated techprofile for ponports successfully",
662 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530663 return nil
664}
665
npujarec5762e2020-01-01 14:08:48 +0530666func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530667 portNo uint32, uplinkClassifier map[string]interface{},
668 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800669 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700670 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530671 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800672 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700673 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530674 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530675}
676
npujarec5762e2020-01-01 14:08:48 +0530677func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530678 portNo uint32, downlinkClassifier map[string]interface{},
679 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800680 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700681 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530682 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
683 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400684 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
685 if vlan, exists := downlinkClassifier[VlanVid]; exists {
686 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700687 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400688 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
689 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800690 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400691 }
692 }
693 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530694 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400695
Manikkaraj k884c1242019-04-11 16:26:42 +0530696 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700697 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400698 // vlan_vid is a uint32. must be type asserted as such or conversion fails
699 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530700 if ok {
701 downlinkAction[VlanVid] = dlClVid & 0xfff
702 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +0530703 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800704 "reason": "failed to convert VLANID classifier",
705 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530706 }
707
David K. Bainbridge794735f2020-02-11 21:01:37 -0800708 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700709 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530710}
711
npujarec5762e2020-01-01 14:08:48 +0530712func (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 +0530713 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800714 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530715 /* One of the OLT platform (Broadcom BAL) requires that symmetric
716 flows require the same flow_id to be used across UL and DL.
717 Since HSIA flow is the only symmetric flow currently, we need to
718 re-use the flow_id across both direction. The 'flow_category'
719 takes priority over flow_cookie to find any available HSIA_FLOW
720 id for the ONU.
721 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700722 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
723 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530724 "logicalFlow": *logicalFlow})
Girish Gowdrafae935c2020-02-17 19:21:44 +0530725 var vlanPbit uint32 = 0xff // means no pbit
Manikkaraj kb1d51442019-07-23 10:41:02 -0400726 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000727 vlanPbit = classifier[VlanPcp].(uint32)
728 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800729 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +0530730 log.Debugw("pbit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400731 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700732 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530733 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800734 log.Debug("flow-already-exists")
735 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530736 }
npujarec5762e2020-01-01 14:08:48 +0530737 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530738 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530739 return olterrors.NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530740 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800741 classifierProto, err := makeOpenOltClassifierField(classifier)
742 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530743 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530744 }
745 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800746 actionProto, err := makeOpenOltActionField(action)
747 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530748 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530749 }
750 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800751 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530752 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530753 return olterrors.NewErrNotFound("nni-interface-id",
David K. Bainbridge794735f2020-02-11 21:01:37 -0800754 log.Fields{
755 "classifier": classifier,
756 "action": action,
757 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530758 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700759 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
760 OnuId: int32(onuID),
761 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000762 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530763 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700764 AllocId: int32(allocID),
765 NetworkIntfId: int32(networkIntfID),
766 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530767 Classifier: classifierProto,
768 Action: actionProto,
769 Priority: int32(logicalFlow.Priority),
770 Cookie: logicalFlow.Cookie,
771 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800772 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530773 return olterrors.NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530774 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800775 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
776 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
777 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
778 flow.OnuId,
779 flow.UniId,
780 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530781 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800782 }
783 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530784}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000785
David K. Bainbridge794735f2020-02-11 21:01:37 -0800786func (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 +0530787
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530788 networkIntfID, err := getNniIntfID(classifier, action)
789 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530790 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800791 "classifier": classifier,
792 "action": action},
793 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530794 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530795
796 // Clear the action map
797 for k := range action {
798 delete(action, k)
799 }
800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700801 action[TrapToHost] = true
802 classifier[UDPSrc] = uint32(68)
803 classifier[UDPDst] = uint32(67)
804 classifier[PacketTagType] = SingleTag
805 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530806
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700807 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530808 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530809 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800810 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530811 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530812
David K. Bainbridge794735f2020-02-11 21:01:37 -0800813 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 +0530814
815 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530816 return olterrors.NewErrNotFound("flow", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800817 "interface-id": intfID,
818 "gem-port": gemPortID,
819 "cookie": flowStoreCookie},
820 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530821 }
822
823 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
824
David K. Bainbridge794735f2020-02-11 21:01:37 -0800825 classifierProto, err := makeOpenOltClassifierField(classifier)
826 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530827 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530828 }
829 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800830 actionProto, err := makeOpenOltActionField(action)
831 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530832 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530833 }
834
David K. Bainbridge794735f2020-02-11 21:01:37 -0800835 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700836 OnuId: int32(onuID),
837 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530838 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700839 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700840 AllocId: int32(allocID),
841 NetworkIntfId: int32(networkIntfID),
842 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530843 Classifier: classifierProto,
844 Action: actionProto,
845 Priority: int32(logicalFlow.Priority),
846 Cookie: logicalFlow.Cookie,
847 PortNo: portNo}
848
David K. Bainbridge794735f2020-02-11 21:01:37 -0800849 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530850 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800851 }
852 log.Debug("DHCP UL flow added to device successfully")
853 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
854 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
855 dhcpFlow.OnuId,
856 dhcpFlow.UniId,
857 dhcpFlow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530858 return olterrors.NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530859 }
860
David K. Bainbridge794735f2020-02-11 21:01:37 -0800861 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530862}
863
Esin Karamanae41e2b2019-12-17 18:13:13 +0000864//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530865func (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 -0800866 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
867 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000868}
869
870//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530871func (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 -0800872 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000873
874 networkIntfID, err := getNniIntfID(classifier, action)
875 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530876 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800877 "classifier": classifier,
878 "action": action},
879 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000880 }
881
882 // Clear the action map
883 for k := range action {
884 delete(action, k)
885 }
886
887 action[TrapToHost] = true
888 classifier[PacketTagType] = SingleTag
889 delete(classifier, VlanVid)
890
891 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530892 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800893 log.Debug("Flow-exists-not-re-adding")
894 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000895 }
896
npujarec5762e2020-01-01 14:08:48 +0530897 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 +0000898
899 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530900 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800901 "interface-id": intfID,
902 "oni-id": onuID,
903 "cookie": flowStoreCookie,
904 "flow-type": flowType},
905 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000906 }
907
908 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
909
David K. Bainbridge794735f2020-02-11 21:01:37 -0800910 classifierProto, err := makeOpenOltClassifierField(classifier)
911 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530912 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000913 }
914 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800915 actionProto, err := makeOpenOltActionField(action)
916 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530917 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000918 }
919
David K. Bainbridge794735f2020-02-11 21:01:37 -0800920 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000921 OnuId: int32(onuID),
922 UniId: int32(uniID),
923 FlowId: flowID,
924 FlowType: Upstream,
925 AllocId: int32(allocID),
926 NetworkIntfId: int32(networkIntfID),
927 GemportId: int32(gemPortID),
928 Classifier: classifierProto,
929 Action: actionProto,
930 Priority: int32(logicalFlow.Priority),
931 Cookie: logicalFlow.Cookie,
932 PortNo: portNo}
933
David K. Bainbridge794735f2020-02-11 21:01:37 -0800934 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530935 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800936 }
937 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000938
David K. Bainbridge794735f2020-02-11 21:01:37 -0800939 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
940 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
941 flow.OnuId,
942 flow.UniId,
943 flow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530944 return olterrors.NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000945 }
946
David K. Bainbridge794735f2020-02-11 21:01:37 -0800947 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000948}
949
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700950// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Girish Gowdrafae935c2020-02-17 19:21:44 +0530951func (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 -0700952 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 +0530953
954 uplinkClassifier := make(map[string]interface{})
955 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530956
manikkaraj kbf256be2019-03-25 00:13:48 +0530957 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700958 uplinkClassifier[EthType] = uint32(EapEthType)
959 uplinkClassifier[PacketTagType] = SingleTag
960 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530961 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700962 uplinkAction[TrapToHost] = true
963 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530964 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800965 log.Debug("Flow-exists-not-re-adding")
966 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530967 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530968 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530969 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530970 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530971 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800972 "interface-id": intfID,
973 "onu-id": onuID,
974 "coookie": flowStoreCookie},
975 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530976 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700977 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530978
David K. Bainbridge794735f2020-02-11 21:01:37 -0800979 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
980 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530981 return olterrors.NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530982 }
983 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800984 actionProto, err := makeOpenOltActionField(uplinkAction)
985 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530986 return olterrors.NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530987 }
988 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800989 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530990 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530991 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800992 "classifier": classifier,
993 "action": action},
994 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530995 }
996
David K. Bainbridge794735f2020-02-11 21:01:37 -0800997 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700998 OnuId: int32(onuID),
999 UniId: int32(uniID),
1000 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001001 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001002 AllocId: int32(allocID),
1003 NetworkIntfId: int32(networkIntfID),
1004 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301005 Classifier: classifierProto,
1006 Action: actionProto,
1007 Priority: int32(logicalFlow.Priority),
1008 Cookie: logicalFlow.Cookie,
1009 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001010 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301011 return olterrors.NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001012 }
1013 log.Debug("EAPOL UL flow added to device successfully")
1014 flowCategory := "EAPOL"
1015 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1016 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1017 upstreamFlow.OnuId,
1018 upstreamFlow.UniId,
1019 upstreamFlow.FlowId,
1020 /* lowCategory, */
1021 flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301022 return olterrors.NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301023 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301024
manikkaraj kbf256be2019-03-25 00:13:48 +05301025 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001026 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301027}
1028
David K. Bainbridge794735f2020-02-11 21:01:37 -08001029func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001030 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001031
1032 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1033 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1034 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
Andrea Campanella7acc0b92020-02-14 09:20:49 +01001035 if vlanID != ReservedVlan {
1036 vid := vlanID & VlanvIDMask
Harsh Awasthiea45af72019-08-26 02:39:00 -04001037 classifier.OVid = vid
1038 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301039 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001040 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1041 vid := uint32(metadata)
1042 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001043 classifier.IVid = vid
1044 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301045 }
Girish Gowdrafae935c2020-02-17 19:21:44 +05301046 // Use VlanPCPMask (0xff) to signify NO PCP. Else use valid PCP (0 to 7)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001047 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Girish Gowdrafae935c2020-02-17 19:21:44 +05301048 classifier.OPbits = vlanPcp
1049 } else {
1050 classifier.OPbits = VlanPCPMask
manikkaraj kbf256be2019-03-25 00:13:48 +05301051 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001052 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1053 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1054 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1055 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001056 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001057 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1058 classifier.PktTagType = pktTagType
1059
1060 switch pktTagType {
1061 case SingleTag:
1062 case DoubleTag:
1063 case Untagged:
1064 default:
Girish Kumarf26e4882020-03-05 06:49:10 +00001065 return nil, olterrors.NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil)
manikkaraj kbf256be2019-03-25 00:13:48 +05301066 }
1067 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001068 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301069}
1070
David K. Bainbridge794735f2020-02-11 21:01:37 -08001071func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001072 var actionCmd openoltpb2.ActionCmd
1073 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301074 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001075 if _, ok := actionInfo[PopVlan]; ok {
1076 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301077 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001078 } else if _, ok := actionInfo[PushVlan]; ok {
1079 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301080 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001081 } else if _, ok := actionInfo[TrapToHost]; ok {
1082 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301083 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00001084 return nil, olterrors.NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil)
manikkaraj kbf256be2019-03-25 00:13:48 +05301085 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001086 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301087}
1088
Manikkaraj kb1d51442019-07-23 10:41:02 -04001089func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1090 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301091}
1092
Gamze Abakafee36392019-10-03 11:17:24 +00001093// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301094func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1095 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001096 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001097 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301098 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001099 olterrors.NewErrAdapter("delete-tech-profile-failed", nil, err).Log()
Girish Gowdra54934262019-11-13 14:19:55 +05301100 // return err
1101 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001102 }
1103 }
1104 return nil
1105}
1106
1107// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301108func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001109 if uniPortName == "" {
1110 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1111 }
npujarec5762e2020-01-01 14:08:48 +05301112 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001113 return olterrors.NewErrAdapter("failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName}, err)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001114 }
1115 return nil
1116}
1117
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001118func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301119 if len(classifier) == 0 { // should never happen
1120 log.Error("Invalid classfier object")
1121 return 0
1122 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301123 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301124 var jsonData []byte
1125 var flowString string
1126 var err error
1127 // TODO: Do we need to marshall ??
1128 if jsonData, err = json.Marshal(classifier); err != nil {
1129 log.Error("Failed to encode classifier")
1130 return 0
1131 }
1132 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001133 if gemPortID != 0 {
1134 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301135 }
1136 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001137 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301138 hash := big.NewInt(0)
1139 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301140 generatedHash := hash.Uint64()
1141 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1142 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301143}
1144
npujarec5762e2020-01-01 14:08:48 +05301145func (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 +05301146 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001147 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001148 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1149 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1150 */
1151 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001152 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001153 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001154 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001155 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001156 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301157 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001158 if existingFlows != nil {
1159 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001160 //for _, f := range *existingFlows {
1161 // flows = append(flows, f)
1162 //}
1163 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001164 }
1165 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 +05301166 return &flows
1167}
1168
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001169//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1170// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1171// var intfId uint32
1172// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1173// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1174// */
1175// if flow.AccessIntfId != -1 {
1176// intfId = uint32(flow.AccessIntfId)
1177// } else {
1178// intfId = uint32(flow.NetworkIntfId)
1179// }
1180// // Get existing flows matching flowid for given subscriber from KV store
1181// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1182// if existingFlows != nil {
1183// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1184// for _, f := range *existingFlows {
1185// flows = append(flows, f)
1186// }
1187// }
1188// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1189// return &flows
1190//}
1191
npujarec5762e2020-01-01 14:08:48 +05301192func (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 -04001193 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301194 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001195 log.Debug("Error while Storing flow into KV store")
1196 return err
1197 }
1198 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301199 return nil
1200}
1201
David K. Bainbridge794735f2020-02-11 21:01:37 -08001202func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001203
1204 var intfID uint32
1205 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1206 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1207 */
1208 if deviceFlow.AccessIntfId != -1 {
1209 intfID = uint32(deviceFlow.AccessIntfId)
1210 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001211 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001212 intfID = uint32(deviceFlow.NetworkIntfId)
1213 }
1214
manikkaraj kbf256be2019-03-25 00:13:48 +05301215 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1216 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001217
1218 st, _ := status.FromError(err)
1219 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001220 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001221 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301222 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001223
1224 if err != nil {
1225 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301226 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001227 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001228 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301229 if deviceFlow.GemportId != -1 {
1230 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301231 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301232 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301233 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001234 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001235}
1236
David K. Bainbridge794735f2020-02-11 21:01:37 -08001237func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001238 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1239 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1240 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001241 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1242 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1243 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001244 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001245 }
Girish Kumarf26e4882020-03-05 06:49:10 +00001246 return olterrors.NewErrFlowOp("remove", deviceFlow.FlowId, log.Fields{"deviceFlow": deviceFlow}, err)
serkant.uluderya245caba2019-09-24 23:15:29 -07001247
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001248 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001249 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001250 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301251}
1252
1253/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1254 //update core flows_proxy : flows_proxy.update('/', flows)
1255}
1256
1257func generateStoredId(flowId uint32, direction string)uint32{
1258
David K. Bainbridge82efc492019-09-04 09:57:11 -07001259 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301260 log.Debug("Upstream flow shifting flowid")
1261 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001262 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301263 log.Debug("Downstream flow not shifting flowid")
1264 return flowId
1265 }else{
1266 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1267 return flowId
1268 }
1269}
1270
1271*/
1272
David K. Bainbridge794735f2020-02-11 21:01:37 -08001273func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001274
1275 classifierInfo := make(map[string]interface{})
1276 actionInfo := make(map[string]interface{})
1277
1278 classifierInfo[EthType] = uint32(LldpEthType)
1279 classifierInfo[PacketTagType] = Untagged
1280 actionInfo[TrapToHost] = true
1281
1282 // LLDP flow is installed to trap LLDP packets on the NNI port.
1283 // We manage flow_id resource pool on per PON port basis.
1284 // Since this situation is tricky, as a hack, we pass the NNI port
1285 // index (network_intf_id) as PON port Index for the flow_id resource
1286 // pool. Also, there is no ONU Id available for trapping LLDP packets
1287 // on NNI port, use onu_id as -1 (invalid)
1288 // ****************** CAVEAT *******************
1289 // This logic works if the NNI Port Id falls within the same valid
1290 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1291 // we need to have a re-look at this.
1292 // *********************************************
1293
1294 var onuID = -1
1295 var uniID = -1
1296 var gemPortID = -1
1297
David K. Bainbridge794735f2020-02-11 21:01:37 -08001298 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1299 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301300 return olterrors.NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001301 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001302 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301303 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001304 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001305 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001306 }
npujarec5762e2020-01-01 14:08:48 +05301307 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001308
1309 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301310 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001311 "interface-id": networkInterfaceID,
1312 "onu-id": onuID,
1313 "uni-id": uniID,
1314 "gem-port-id": gemPortID,
1315 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00001316 err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001317 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001318 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1319 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001320 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001321 }
1322 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001323 actionProto, err := makeOpenOltActionField(actionInfo)
1324 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001325 return olterrors.NewErrInvalidValue(log.Fields{"action": actionInfo}, err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001326 }
1327 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1328
1329 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1330 OnuId: int32(onuID), // OnuId not required
1331 UniId: int32(uniID), // UniId not used
1332 FlowId: flowID,
1333 FlowType: Downstream,
1334 NetworkIntfId: int32(networkInterfaceID),
1335 GemportId: int32(gemPortID),
1336 Classifier: classifierProto,
1337 Action: actionProto,
1338 Priority: int32(flow.Priority),
1339 Cookie: flow.Cookie,
1340 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001341 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001342 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001343 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001344 log.Debug("LLDP trap on NNI flow added to device successfully")
1345 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1346 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1347 int32(onuID),
1348 int32(uniID),
1349 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001350 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001351 }
1352 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301353}
1354
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301355func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001356 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1357}
1358
1359//getOnuChildDevice to fetch onu
1360func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1361 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1362 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001363 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1364 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301365 return nil, olterrors.NewErrNotFound("onu", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001366 "interface-id": parentPortNo,
1367 "onu-id": onuID},
Girish Kumarf26e4882020-03-05 06:49:10 +00001368 err)
manikkaraj kbf256be2019-03-25 00:13:48 +05301369 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301370 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1371 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301372}
1373
1374func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001375 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301376 return nil
1377}
1378
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001379func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1380 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301381}
1382
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001383func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001384 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001385 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001386 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001387 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001388}
1389
Girish Gowdra6b130582019-11-20 16:45:20 +05301390func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1391 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1392 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001393 return olterrors.NewErrNotFound("onu-child-device", log.Fields{"onuId": onuID, "intfID": intfID}, err)
Girish Gowdra6b130582019-11-20 16:45:20 +05301394 }
1395
1396 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1397 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1398 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1399 delGemPortMsg,
1400 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1401 f.deviceHandler.deviceType,
1402 onuDevice.Type,
1403 onuDevice.Id,
1404 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001405 return olterrors.NewErrCommunication("send-delete-gem-port-to-onu-adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
Girish Gowdra6b130582019-11-20 16:45:20 +05301406 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
Girish Kumarf26e4882020-03-05 06:49:10 +00001407 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId}, sendErr)
Girish Gowdra6b130582019-11-20 16:45:20 +05301408 }
1409 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1410 return nil
1411}
1412
1413func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1414 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1415 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001416 return olterrors.NewErrNotFound("onu-child-device", log.Fields{"onuId": onuID, "intfID": intfID}, err)
Girish Gowdra6b130582019-11-20 16:45:20 +05301417 }
1418
1419 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1420 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1421 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1422 delTcontMsg,
1423 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1424 f.deviceHandler.deviceType,
1425 onuDevice.Type,
1426 onuDevice.Id,
1427 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001428 return olterrors.NewErrCommunication("send-delete-tcont-to-onu-adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
Girish Gowdra6b130582019-11-20 16:45:20 +05301429 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
Girish Kumarf26e4882020-03-05 06:49:10 +00001430 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId}, sendErr)
Girish Gowdra6b130582019-11-20 16:45:20 +05301431 }
1432 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1433 return nil
1434}
1435
Girish Gowdra3d633032019-12-10 16:37:05 +05301436func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1437 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1438 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1439 if val.(int) > 0 {
1440 pnFlDels := val.(int) - 1
1441 if pnFlDels > 0 {
1442 log.Debugw("flow delete succeeded, more pending",
1443 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1444 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1445 } else {
1446 log.Debugw("all pending flow deletes handled, removing entry from map",
1447 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1448 f.pendingFlowDelete.Delete(pnFlDelKey)
1449 }
1450 }
1451 } else {
1452 log.Debugw("no pending delete flows found",
1453 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1454
1455 }
1456
1457}
1458
Girish Gowdrac3037402020-01-22 20:29:53 +05301459// Once the gemport is released for a given onu, it also has to be cleared from local cache
1460// which was used for deriving the gemport->logicalPortNo during packet-in.
1461// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1462// is conveyed to ONOS during packet-in OF message.
1463func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1464 f.lockCache.Lock()
1465 defer f.lockCache.Unlock()
1466 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001467 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301468 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001469 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301470 // If the gemport is found, delete it from local cache.
1471 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001472 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1473 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301474 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001475 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301476 break
1477 }
1478 }
1479 break
1480 }
1481 }
1482}
1483
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301484//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301485func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301486 gemPortID int32, flowID uint32, flowDirection string,
1487 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001488
Chaitrashree G S90a17952019-11-14 21:51:21 -05001489 tpID, err := getTpIDFromFlow(flow)
1490 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001491 return olterrors.NewErrNotFound("tpid", log.Fields{"flow": flow, "pon": Intf, "onuID": onuID, "uniID": uniID}, err)
Chaitrashree G S90a17952019-11-14 21:51:21 -05001492 }
Gamze Abakafee36392019-10-03 11:17:24 +00001493
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001494 if len(updatedFlows) >= 0 {
1495 // There are still flows referencing the same flow_id.
1496 // So the flow should not be freed yet.
1497 // For ex: Case of HSIA where same flow is shared
1498 // between DS and US.
Girish Kumarf26e4882020-03-05 06:49:10 +00001499 if err := f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows); err != nil {
1500 olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": updatedFlows}, err).Log()
1501 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001502 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301503 // Do this for subscriber flows only (not trap from NNI flows)
1504 if onuID != -1 && uniID != -1 {
1505 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1506 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1507 log.Debugw("creating entry for pending flow delete",
1508 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1509 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1510 } else {
1511 pnFlDels := val.(int) + 1
1512 log.Debugw("updating flow delete entry",
1513 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1514 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1515 }
1516
1517 defer f.deletePendingFlows(Intf, onuID, uniID)
1518 }
1519
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301520 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301521 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001522
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301523 uni := getUniPortPath(Intf, onuID, uniID)
1524 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001525 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301526 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Girish Kumarf26e4882020-03-05 06:49:10 +00001527 if err != nil || techprofileInst == nil { // This should not happen, something wrong in KV backend transaction
1528 return olterrors.NewErrNotFound("tech-profile-in-kv-store", log.Fields{"tpID": tpID, "path": tpPath}, err)
Gamze Abakafee36392019-10-03 11:17:24 +00001529 }
1530
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301531 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001532 if f.isGemPortUsedByAnotherFlow(gemPK) {
1533 flowIDs := f.flowsUsedByGemPort[gemPK]
1534 for i, flowIDinMap := range flowIDs {
1535 if flowIDinMap == flowID {
1536 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301537 // everytime flowsUsedByGemPort cache is updated the same should be updated
1538 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001539 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301540 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001541 break
1542 }
1543 }
1544 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301545 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001546 }
Gamze Abakafee36392019-10-03 11:17:24 +00001547 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301548 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001549 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1550 // 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 +05301551 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301552 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001553 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301554 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1555 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001556 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301557 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1558 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001559 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301560 // Delete the gem port on the ONU.
1561 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1562 log.Errorw("error processing delete gem-port towards onu",
1563 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1564 }
Gamze Abakafee36392019-10-03 11:17:24 +00001565
npujarec5762e2020-01-01 14:08:48 +05301566 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001567 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301568 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1569 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1570 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1571 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1572 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301573 // Delete the TCONT on the ONU.
1574 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1575 log.Errorw("error processing delete tcont towards onu",
1576 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1577 }
Gamze Abakafee36392019-10-03 11:17:24 +00001578 }
1579 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001580 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301581 return nil
1582}
1583
David K. Bainbridge794735f2020-02-11 21:01:37 -08001584// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301585func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301586
1587 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001588
1589 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301590 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001591 return
1592 }
1593
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301594 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301595 classifierInfo := make(map[string]interface{})
1596
1597 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1598 if err != nil {
1599 log.Error(err)
1600 return
1601 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301602
David K. Bainbridge794735f2020-02-11 21:01:37 -08001603 onuID := int32(onu)
1604 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301605
1606 for _, field := range flows.GetOfbFields(flow) {
1607 if field.Type == flows.IP_PROTO {
1608 classifierInfo[IPProto] = field.GetIpProto()
1609 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1610 }
1611 }
1612 log.Debugw("Extracted access info from flow to be deleted",
1613 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1614
1615 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1616 onuID = -1
1617 uniID = -1
1618 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001619 Intf, err = IntfIDFromNniPortNum(inPort)
1620 if err != nil {
1621 log.Errorw("invalid-in-port-number",
1622 log.Fields{
1623 "port-number": inPort,
1624 "error": err})
1625 return
1626 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301627 }
npujarec5762e2020-01-01 14:08:48 +05301628 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001629 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301630 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301631 if flowInfo == nil {
1632 log.Debugw("No FlowInfo found found in KV store",
1633 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1634 return
1635 }
1636 updatedFlows = nil
1637 for _, flow := range *flowInfo {
1638 updatedFlows = append(updatedFlows, flow)
1639 }
1640
1641 for i, storedFlow := range updatedFlows {
1642 if flow.Id == storedFlow.LogicalFlowID {
1643 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1644 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001645 // DKB
1646 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1647 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1648 return
1649 }
1650 log.Debug("Flow removed from device successfully")
1651 //Remove the Flow from FlowInfo
1652 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1653 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1654 flowID, flowDirection, portNum, updatedFlows); err != nil {
1655 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301656 return
1657 }
1658 }
1659 }
1660 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001661}
1662
Esin Karamanccb714b2019-11-29 15:02:06 +00001663//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1664// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301665func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001666 classifierInfo := make(map[string]interface{})
1667 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301668 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001669
1670 if err != nil {
1671 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1672 return
1673 }
1674
David K. Bainbridge794735f2020-02-11 21:01:37 -08001675 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1676 if err != nil {
1677 // DKB
1678 log.Errorw("invalid-in-port-number",
1679 log.Fields{
1680 "port-number": inPort,
1681 "error": err})
1682 return
1683 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001684 var onuID = int32(NoneOnuID)
1685 var uniID = int32(NoneUniID)
1686 var flowID uint32
1687 var updatedFlows []rsrcMgr.FlowInfo
1688
npujarec5762e2020-01-01 14:08:48 +05301689 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001690
1691 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301692 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001693 if flowInfo == nil {
1694 log.Debugw("No multicast FlowInfo found in the KV store",
1695 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1696 continue
1697 }
1698 updatedFlows = nil
1699 for _, flow := range *flowInfo {
1700 updatedFlows = append(updatedFlows, flow)
1701 }
1702 for i, storedFlow := range updatedFlows {
1703 if flow.Id == storedFlow.LogicalFlowID {
1704 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1705 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1706 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001707 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1708 // DKB
1709 log.Errorw("failed-to-remove-multicast-flow",
1710 log.Fields{
1711 "flow-id": flow.Id,
1712 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001713 return
1714 }
1715 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1716 //Remove the Flow from FlowInfo
1717 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301718 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001719 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1720 return
1721 }
1722 //release flow id
1723 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301724 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001725 }
1726 }
1727 }
1728}
1729
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001730//RemoveFlow removes the flow from the device
Girish Gowdracefae192020-03-19 18:14:10 -07001731func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001732 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301733 var direction string
1734 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001735
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301736 for _, action := range flows.GetActions(flow) {
1737 if action.Type == flows.OUTPUT {
1738 if out := action.GetOutput(); out != nil {
1739 actionInfo[Output] = out.GetPort()
1740 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1741 } else {
1742 log.Error("Invalid output port in action")
Girish Gowdracefae192020-03-19 18:14:10 -07001743 return olterrors.NewErrInvalidValue(log.Fields{"invalid-out-port-action": 0}, nil)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001744 }
1745 }
1746 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001747
1748 if flows.HasGroup(flow) {
1749 direction = Multicast
Girish Gowdracefae192020-03-19 18:14:10 -07001750 f.clearFlowFromResourceManager(ctx, flow, direction)
1751 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001752 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301753 direction = Upstream
1754 } else {
1755 direction = Downstream
1756 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301757
Girish Gowdracefae192020-03-19 18:14:10 -07001758 _, intfID, onuID, uniID, _, _, err := FlowExtractInfo(flow, direction)
1759 if err != nil {
1760 return err
1761 }
1762
1763 userKey := tpLockKey{intfID, onuID, uniID}
1764
1765 // Serialize flow removes on a per subscriber basis
1766 if f.perUserFlowHandleLock.TryLock(userKey) {
1767 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
1768 f.perUserFlowHandleLock.Unlock(userKey)
1769 } else {
1770 // Ideally this should never happen
1771 log.Errorw("failed to acquire lock to remove flow, flow remove aborted", log.Fields{"flow": flow})
1772 return errors.New("failed-to-acquire-per-user-lock")
1773 }
1774
1775 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001776}
1777
Girish Gowdra3d633032019-12-10 16:37:05 +05301778func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1779 uniID uint32, ch chan bool) {
1780 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1781 for {
1782 select {
1783 case <-time.After(20 * time.Millisecond):
1784 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1785 log.Debug("pending flow deletes completed")
1786 ch <- true
1787 return
1788 }
1789 case <-ctx.Done():
1790 log.Error("flow delete wait handler routine canceled")
1791 return
1792 }
1793 }
1794}
1795
Esin Karamanae41e2b2019-12-17 18:13:13 +00001796//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1797func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1798 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1799 if ethType, ok := classifierInfo[EthType]; ok {
1800 if ethType.(uint32) == IPv4EthType {
1801 if ipProto, ok := classifierInfo[IPProto]; ok {
1802 if ipProto.(uint32) == IgmpProto {
1803 return true
1804 }
1805 }
1806 }
1807 }
1808 }
1809 return false
1810}
1811
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001812// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301813// nolint: gocyclo
Andrea Campanellac63bba92020-03-10 17:01:04 +01001814func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001815 classifierInfo := make(map[string]interface{})
1816 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001817 var UsMeterID uint32
1818 var DsMeterID uint32
1819
1820 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001821 formulateClassifierInfoFromFlow(classifierInfo, flow)
1822
1823 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1824 if err != nil {
1825 // Error logging is already done in the called function
1826 // So just return in case of error
Andrea Campanellac63bba92020-03-10 17:01:04 +01001827 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05301828 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001829
Esin Karamanccb714b2019-11-29 15:02:06 +00001830 if flows.HasGroup(flow) {
1831 // handle multicast flow
Andrea Campanellac63bba92020-03-10 17:01:04 +01001832 return f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001833 }
1834
manikkaraj k17652a72019-05-06 09:06:36 -04001835 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001836 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1837 if err != nil {
1838 // error if any, already logged in the called function
Andrea Campanellac63bba92020-03-10 17:01:04 +01001839 return err
manikkaraj k17652a72019-05-06 09:06:36 -04001840 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001841
David K. Bainbridge82efc492019-09-04 09:57:11 -07001842 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1843 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001844
Humera Kouser94d7a842019-08-25 19:04:32 -04001845 if ethType, ok := classifierInfo[EthType]; ok {
1846 if ethType.(uint32) == LldpEthType {
1847 log.Info("Adding LLDP flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001848 return f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001849 }
1850 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001851 if ipProto, ok := classifierInfo[IPProto]; ok {
1852 if ipProto.(uint32) == IPProtoDhcp {
1853 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301854 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001855 log.Debug("trap-dhcp-from-nni-flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001856 return f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001857 }
1858 }
1859 }
1860 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001861 if isIgmpTrapDownstreamFlow(classifierInfo) {
1862 log.Debug("trap-igmp-from-nni-flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001863 return f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001864 }
A R Karthick1f85b802019-10-11 05:06:05 +00001865
1866 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301867 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001868
Chaitrashree G S90a17952019-11-14 21:51:21 -05001869 TpID, err := getTpIDFromFlow(flow)
1870 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001871 return olterrors.NewErrNotFound("tpid-for-flow", log.Fields{"flow": flow, "pon": IntfID, "onuID": onuID, "uniID": uniID}, err)
Chaitrashree G S90a17952019-11-14 21:51:21 -05001872 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001873 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001874 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001875 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001876 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1877 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001878 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001879 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1880
1881 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301882
1883 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1884 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1885 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 +05301886 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301887 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301888 pendingFlowDelComplete := make(chan bool)
1889 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1890 select {
1891 case <-pendingFlowDelComplete:
1892 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301893 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301894
1895 case <-time.After(10 * time.Second):
Girish Kumarf26e4882020-03-05 06:49:10 +00001896 return olterrors.NewErrTimeout("pending-flow-deletes", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID}, nil)
Girish Gowdra3d633032019-12-10 16:37:05 +05301897 }
1898 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01001899 return nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001900}
1901
Esin Karamanccb714b2019-11-29 15:02:06 +00001902// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001903func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001904 classifierInfo[PacketTagType] = DoubleTag
1905 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1906
npujarec5762e2020-01-01 14:08:48 +05301907 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001908 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001909 return olterrors.NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001910 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001911 //this variable acts like a switch. When it is set, multicast flows are classified by eth_dst.
1912 //otherwise, classification is based on ipv4_dst by default.
1913 //the variable can be configurable in the future; it can be read from a configuration path in the kv store.
1914 mcastFlowClassificationByEthDst := false
1915
1916 if mcastFlowClassificationByEthDst {
1917 //replace ipDst with ethDst
1918 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1919 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1920 // replace ipv4_dst classifier with eth_dst
1921 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1922 delete(classifierInfo, Ipv4Dst)
1923 classifierInfo[EthDst] = multicastMac
1924 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1925 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001926 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001927 delete(classifierInfo, EthType)
Esin Karamanccb714b2019-11-29 15:02:06 +00001928
David K. Bainbridge794735f2020-02-11 21:01:37 -08001929 onuID := NoneOnuID
1930 uniID := NoneUniID
1931 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001932
David K. Bainbridge794735f2020-02-11 21:01:37 -08001933 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1934 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001935 return olterrors.NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001936 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001937
David K. Bainbridge794735f2020-02-11 21:01:37 -08001938 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301939 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001940 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1941 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001942 }
npujarec5762e2020-01-01 14:08:48 +05301943 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001944 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301945 return olterrors.NewErrNotFound("multicast-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001946 "interface-id": networkInterfaceID,
1947 "onu-id": onuID,
1948 "uni-id": uniID,
1949 "gem-port-id": gemPortID,
1950 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00001951 err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001952 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001953 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1954 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001955 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001956 }
1957 groupID := actionInfo[GroupID].(uint32)
1958 multicastFlow := openoltpb2.Flow{
1959 FlowId: flowID,
1960 FlowType: Multicast,
1961 NetworkIntfId: int32(networkInterfaceID),
1962 GroupId: groupID,
1963 Classifier: classifierProto,
1964 Priority: int32(flow.Priority),
1965 Cookie: flow.Cookie}
1966
David K. Bainbridge794735f2020-02-11 21:01:37 -08001967 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001968 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001969 }
1970 log.Debug("multicast flow added to device successfully")
1971 //get cached group
1972 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1973 if err == nil {
1974 //calling groupAdd to set group members after multicast flow creation
Andrea Campanellac63bba92020-03-10 17:01:04 +01001975 if err = f.ModifyGroup(ctx, group); err == nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001976 //cached group can be removed now
1977 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Andrea Campanellac63bba92020-03-10 17:01:04 +01001978 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00001979 return olterrors.NewErrGroupOp("modify", groupID, log.Fields{"group": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001980 }
1981 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001982
1983 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1984 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1985 int32(onuID),
1986 int32(uniID),
1987 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001988 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001989 }
1990 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001991}
1992
1993//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301994func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001995 if _, ok := classifierInfo[InPort]; ok {
1996 return classifierInfo[InPort].(uint32), nil
1997 }
1998 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301999 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002000 if e == nil && len(nniPorts) > 0 {
2001 return nniPorts[0], nil
2002 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302003 return 0, olterrors.NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002004}
2005
2006// AddGroup add or update the group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002007func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002008 log.Infow("add-group", log.Fields{"group": group})
2009 if group == nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002010 return olterrors.NewErrInvalidValue(log.Fields{"group": group}, nil)
Esin Karamanccb714b2019-11-29 15:02:06 +00002011 }
2012
2013 groupToOlt := openoltpb2.Group{
2014 GroupId: group.Desc.GroupId,
2015 Command: openoltpb2.Group_SET_MEMBERS,
2016 Action: f.buildGroupAction(),
2017 }
2018
2019 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302020 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002021 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002022 return olterrors.NewErrAdapter("add-group-operation-failed", log.Fields{"groupToOlt": groupToOlt}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002023 }
2024 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302025 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002026 return olterrors.NewErrPersistence("add", "flow-group", group.Desc.GroupId, log.Fields{"group": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002027 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002028 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2029 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002030}
2031
2032//buildGroupAction creates and returns a group action
2033func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2034 var actionCmd openoltpb2.ActionCmd
2035 var action openoltpb2.Action
2036 action.Cmd = &actionCmd
2037 //pop outer vlan
2038 action.Cmd.RemoveOuterTag = true
2039 return &action
2040}
2041
2042// ModifyGroup updates the group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002043func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002044 log.Infow("modify-group", log.Fields{"group": group})
2045 if group == nil || group.Desc == nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002046 return olterrors.NewErrInvalidValue(log.Fields{"group": group, "groupDesc": group.Desc}, nil)
Esin Karamanccb714b2019-11-29 15:02:06 +00002047 }
2048
Andrea Campanellac63bba92020-03-10 17:01:04 +01002049 newGroup := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
Esin Karamanccb714b2019-11-29 15:02:06 +00002050 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302051 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002052
2053 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002054 return olterrors.NewErrNotFound("flow-group-in-kv-store", log.Fields{"groupId": group.Desc.GroupId}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002055 }
2056
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002057 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002058 if groupExists {
2059 // group already exists
2060 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002061 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002062 } else {
2063 current = f.buildGroup(group.Desc.GroupId, nil)
2064 }
2065
Andrea Campanellac63bba92020-03-10 17:01:04 +01002066 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": newGroup})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002067 // get members to be added
Andrea Campanellac63bba92020-03-10 17:01:04 +01002068 membersToBeAdded := f.findDiff(current, newGroup)
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002069 // get members to be removed
Andrea Campanellac63bba92020-03-10 17:01:04 +01002070 membersToBeRemoved := f.findDiff(newGroup, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002071
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002072 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2073 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002074
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002075 groupToOlt := openoltpb2.Group{
2076 GroupId: group.Desc.GroupId,
2077 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002078 var errAdd, errRemoved error
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002079 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2080 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2081 groupToOlt.Members = membersToBeAdded
2082 //execute addMembers
Andrea Campanellac63bba92020-03-10 17:01:04 +01002083 errAdd = f.callGroupAddRemove(&groupToOlt)
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002084 }
2085 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2086 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2087 groupToOlt.Members = membersToBeRemoved
2088 //execute removeMembers
Andrea Campanellac63bba92020-03-10 17:01:04 +01002089 errRemoved = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002090 }
2091
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002092 //save the modified group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002093 if errAdd == nil && errRemoved == nil {
npujarec5762e2020-01-01 14:08:48 +05302094 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002095 return olterrors.NewErrPersistence("add", "flow-group", group.Desc.GroupId, log.Fields{"group": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002096 }
2097 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002098 } else {
2099 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2100 log.Fields{"group": group})
Andrea Campanellac63bba92020-03-10 17:01:04 +01002101 if errAdd != nil {
2102 return errAdd
2103 }
2104 return errRemoved
Esin Karamanccb714b2019-11-29 15:02:06 +00002105 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002106 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002107}
2108
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002109//callGroupAddRemove performs add/remove buckets operation for the indicated group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002110func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) error {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002111 if err := f.performGroupOperation(group); err != nil {
2112 st, _ := status.FromError(err)
2113 //ignore already exists error code
2114 if st.Code() != codes.AlreadyExists {
Andrea Campanellac63bba92020-03-10 17:01:04 +01002115 return olterrors.NewErrGroupOp("groupAddRemove", group.GroupId, log.Fields{"status": st}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002116 }
2117 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002118 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002119}
2120
2121//findDiff compares group members and finds members which only exists in groups2
2122func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2123 var members []*openoltpb2.GroupMember
2124 for _, bucket := range group2.Members {
2125 if !f.contains(group1.Members, bucket) {
2126 // bucket does not exist and must be added
2127 members = append(members, bucket)
2128 }
2129 }
2130 return members
2131}
2132
2133//contains returns true if the members list contains the given member; false otherwise
2134func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2135 for _, groupMember := range members {
2136 if groupMember.InterfaceId == member.InterfaceId {
2137 return true
2138 }
2139 }
2140 return false
2141}
2142
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002143//performGroupOperation call performGroupOperation operation of openolt proto
2144func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002145 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2146 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2147 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002148 return olterrors.NewErrAdapter("group-operation-failed", log.Fields{"groupToOlt": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002149 }
Girish Kumarf26e4882020-03-05 06:49:10 +00002150 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002151}
2152
2153//buildGroup build openoltpb2.Group from given group id and bucket list
2154func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2155 group := openoltpb2.Group{
2156 GroupId: groupID}
2157 // create members of the group
2158 if buckets != nil {
2159 for _, ofBucket := range buckets {
2160 member := f.buildMember(ofBucket)
2161 if member != nil && !f.contains(group.Members, member) {
2162 group.Members = append(group.Members, member)
2163 }
2164 }
2165 }
2166 return &group
2167}
2168
2169//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2170func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2171 var outPort uint32
2172 outPortFound := false
2173 for _, ofAction := range ofBucket.Actions {
2174 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2175 outPort = ofAction.GetOutput().Port
2176 outPortFound = true
2177 }
2178 }
2179
2180 if !outPortFound {
2181 log.Debugw("bucket skipped since no out port found in it",
2182 log.Fields{"ofBucket": ofBucket})
2183 return nil
2184 }
2185 interfaceID := IntfIDFromUniPortNum(outPort)
2186 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2187 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2188 member := openoltpb2.GroupMember{
2189 InterfaceId: interfaceID,
2190 InterfaceType: openoltpb2.GroupMember_PON,
2191 GemPortId: groupInfo.gemPortID,
2192 Priority: groupInfo.servicePriority,
2193 }
2194 //add member to the group
2195 return &member
2196 }
2197 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2198 log.Fields{"ofBucket": ofBucket})
2199 return nil
2200}
2201
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002202//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002203func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002204
2205 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302206 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002207 return olterrors.NewErrNotFound("onu-child-device", log.Fields{"onuId": onuID, "intfID": intfID}, err)
manikkaraj kbf256be2019-03-25 00:13:48 +05302208 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302209 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002210
Manikkaraj kb1d51442019-07-23 10:41:02 -04002211 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002212 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002213 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2214 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2215 tpDownloadMsg,
2216 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2217 f.deviceHandler.deviceType,
2218 onuDevice.Type,
2219 onuDevice.Id,
2220 onuDevice.ProxyAddress.DeviceId, "")
2221 if sendErr != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002222 return olterrors.NewErrCommunication("send-techprofile-download-request", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
manikkaraj k17652a72019-05-06 09:06:36 -04002223 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
Girish Kumarf26e4882020-03-05 06:49:10 +00002224 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId}, sendErr)
manikkaraj k17652a72019-05-06 09:06:36 -04002225 }
2226 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302227 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302228}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002229
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302230//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302231func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302232
2233 f.lockCache.Lock()
2234 defer f.lockCache.Unlock()
2235 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2236 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002237 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2238 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302239 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2240 return
2241 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002242 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2243}
2244
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302245//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302246func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302247 f.lockCache.Lock()
2248 defer f.lockCache.Unlock()
2249 onugem := f.onuGemInfo[intfID]
2250 // update the gem to the local cache as well as to kv strore
2251 for idx, onu := range onugem {
2252 if onu.OnuID == onuID {
2253 // check if gem already exists , else update the cache and kvstore
2254 for _, gem := range onu.GemPorts {
2255 if gem == gemPort {
2256 log.Debugw("Gem already in cache, no need to update cache and kv store",
2257 log.Fields{"gem": gemPort})
2258 return
2259 }
2260 }
2261 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2262 f.onuGemInfo[intfID] = onugem
2263 }
2264 }
npujarec5762e2020-01-01 14:08:48 +05302265 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302266 if err != nil {
2267 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002268 return
2269 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002270}
2271
2272// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002273
2274//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2275func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302276
2277 f.lockCache.Lock()
2278 defer f.lockCache.Unlock()
2279
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002280 log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPortId": gemPortID})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302281 // get onuid from the onugem info cache
2282 onugem := f.onuGemInfo[intfID]
2283 for _, onu := range onugem {
2284 for _, gem := range onu.GemPorts {
2285 if gem == gemPortID {
2286 return onu.OnuID, nil
2287 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002288 }
2289 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302290 return uint32(0), olterrors.NewErrNotFound("onu-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002291 "serial-number": serialNumber,
2292 "interface-id": intfID,
2293 "gem-port-id": gemPortID},
Girish Kumarf26e4882020-03-05 06:49:10 +00002294 nil)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002295}
2296
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002297//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302298func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002299 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002300 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002301 var err error
2302
2303 if packetIn.IntfType == "pon" {
2304 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002305 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002306 // Called method is returning error with all data populated; just return the same
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002307 return logicalPortNum, err
2308 }
2309 if packetIn.PortNo != 0 {
2310 logicalPortNum = packetIn.PortNo
2311 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002312 uniID := uint32(0) // FIXME - multi-uni support
2313 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002314 }
2315 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302316 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002317 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002318 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002319 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002320 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2321 "logicalPortNum": logicalPortNum,
2322 "IntfType": packetIn.IntfType,
2323 "packet": hex.EncodeToString(packetIn.Pkt),
2324 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002325 return logicalPortNum, nil
2326}
2327
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002328//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302329func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002330 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002331 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302332
2333 f.lockCache.Lock()
2334 defer f.lockCache.Unlock()
2335 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2336
2337 gemPortID, ok := f.packetInGemPort[pktInkey]
2338 if ok {
2339 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2340 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002341 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302342 //If gem is not found in cache try to get it from kv store, if found in kv store, update the cache and return.
npujarec5762e2020-01-01 14:08:48 +05302343 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302344 if err == nil {
2345 if gemPortID != 0 {
2346 f.packetInGemPort[pktInkey] = gemPortID
2347 log.Debugw("Found gem port from kv store and updating cache with gemport",
2348 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2349 return gemPortID, nil
2350 }
2351 }
Girish Kumarf26e4882020-03-05 06:49:10 +00002352 return uint32(0), olterrors.NewErrNotFound("gem-port", log.Fields{"pktinkey": pktInkey, "gem": gemPortID}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002353}
2354
npujarec5762e2020-01-01 14:08:48 +05302355func installFlowOnAllGemports(ctx context.Context,
2356 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002357 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002358 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302359 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302360 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302361 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302362 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002363 args map[string]uint32,
2364 classifier map[string]interface{}, action map[string]interface{},
2365 logicalFlow *ofp.OfpFlowStats,
2366 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302367 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002368 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002369 vlanID ...uint32) {
2370 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302371
2372 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2373 var gemPortID uint32
2374 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2375 // We need to trim prefix "0b", before further processing
2376 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2377 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2378 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2379 // If a particular character in the string is set to '1', identify the index of this character from
2380 // the LSB position which marks the PCP bit consumed by the given gem port.
2381 // This PCP bit now becomes a classifier in the flow.
2382 if pbitSet == BinaryBit1 {
2383 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2384 gemPortID = gemPortAttribute.GemportID
2385 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2386 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2387 } else if FlowType == EapolFlow {
2388 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2389 } else {
2390 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2391 return
2392 }
2393 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002394 }
2395 }
2396}
2397
David K. Bainbridge794735f2020-02-11 21:01:37 -08002398func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002399 log.Debug("Adding trap-dhcp-of-nni-flow")
2400 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002401 classifier[PacketTagType] = DoubleTag
2402 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002403 /* We manage flowId resource pool on per PON port basis.
2404 Since this situation is tricky, as a hack, we pass the NNI port
2405 index (network_intf_id) as PON port Index for the flowId resource
2406 pool. Also, there is no ONU Id available for trapping DHCP packets
2407 on NNI port, use onu_id as -1 (invalid)
2408 ****************** CAVEAT *******************
2409 This logic works if the NNI Port Id falls within the same valid
2410 range of PON Port Ids. If this doesn't work for some OLT Vendor
2411 we need to have a re-look at this.
2412 *********************************************
2413 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002414 onuID := -1
2415 uniID := -1
2416 gemPortID := -1
2417 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002418 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302419 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302420 return olterrors.NewErrNotFound("nni-intreface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002421 "classifier": classifier,
2422 "action": action},
Girish Kumarf26e4882020-03-05 06:49:10 +00002423 err)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302424 }
2425
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002426 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302427 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002428 log.Debug("Flow-exists-not-re-adding")
2429 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002430 }
npujarec5762e2020-01-01 14:08:48 +05302431 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002432 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302433 return olterrors.NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002434 "interface-id": networkInterfaceID,
2435 "onu-id": onuID,
2436 "uni-id": uniID,
2437 "gem-port-id": gemPortID,
2438 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00002439 err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002440 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002441 classifierProto, err := makeOpenOltClassifierField(classifier)
2442 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002443 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002444 }
2445 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002446 actionProto, err := makeOpenOltActionField(action)
2447 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002448 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002449 }
2450 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002451 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2452 OnuId: int32(onuID), // OnuId not required
2453 UniId: int32(uniID), // UniId not used
2454 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002455 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002456 AllocId: int32(allocID), // AllocId not used
2457 NetworkIntfId: int32(networkInterfaceID),
2458 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002459 Classifier: classifierProto,
2460 Action: actionProto,
2461 Priority: int32(logicalFlow.Priority),
2462 Cookie: logicalFlow.Cookie,
2463 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002464 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002465 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002466 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002467 log.Debug("DHCP trap on NNI flow added to device successfully")
2468 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2469 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2470 int32(onuID),
2471 int32(uniID),
2472 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002473 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08002474 }
2475 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002476}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002477
Esin Karamanae41e2b2019-12-17 18:13:13 +00002478//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2479func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2480 var packetType string
2481 ovid, ivid := false, false
2482 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2483 vid := vlanID & VlanvIDMask
2484 if vid != ReservedVlan {
2485 ovid = true
2486 }
2487 }
2488 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2489 vid := uint32(metadata)
2490 if vid != ReservedVlan {
2491 ivid = true
2492 }
2493 }
2494 if ovid && ivid {
2495 packetType = DoubleTag
2496 } else if !ovid && !ivid {
2497 packetType = Untagged
2498 } else {
2499 packetType = SingleTag
2500 }
2501 return packetType
2502}
2503
2504//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002505func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002506 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2507 action := make(map[string]interface{})
2508 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2509 action[TrapToHost] = true
2510 /* We manage flowId resource pool on per PON port basis.
2511 Since this situation is tricky, as a hack, we pass the NNI port
2512 index (network_intf_id) as PON port Index for the flowId resource
2513 pool. Also, there is no ONU Id available for trapping packets
2514 on NNI port, use onu_id as -1 (invalid)
2515 ****************** CAVEAT *******************
2516 This logic works if the NNI Port Id falls within the same valid
2517 range of PON Port Ids. If this doesn't work for some OLT Vendor
2518 we need to have a re-look at this.
2519 *********************************************
2520 */
2521 onuID := -1
2522 uniID := -1
2523 gemPortID := -1
2524 allocID := -1
2525 networkInterfaceID, err := getNniIntfID(classifier, action)
2526 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302527 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002528 "classifier": classifier,
2529 "action": action},
Girish Kumarf26e4882020-03-05 06:49:10 +00002530 err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002531 }
2532 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302533 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002534 log.Debug("igmp-flow-exists-not-re-adding")
2535 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002536 }
npujarec5762e2020-01-01 14:08:48 +05302537 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002538 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302539 return olterrors.NewErrNotFound("igmp-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002540 "interface-id": networkInterfaceID,
2541 "onu-id": onuID,
2542 "uni-id": uniID,
2543 "gem-port-id": gemPortID,
2544 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00002545 err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002546 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002547 classifierProto, err := makeOpenOltClassifierField(classifier)
2548 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002549 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002550 }
2551 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002552 actionProto, err := makeOpenOltActionField(action)
2553 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002554 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002555 }
2556 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2557 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2558 OnuId: int32(onuID), // OnuId not required
2559 UniId: int32(uniID), // UniId not used
2560 FlowId: flowID,
2561 FlowType: Downstream,
2562 AllocId: int32(allocID), // AllocId not used
2563 NetworkIntfId: int32(networkInterfaceID),
2564 GemportId: int32(gemPortID), // GemportId not used
2565 Classifier: classifierProto,
2566 Action: actionProto,
2567 Priority: int32(logicalFlow.Priority),
2568 Cookie: logicalFlow.Cookie,
2569 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002570 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002571 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002572 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002573 log.Debug("IGMP Trap on NNI flow added to device successfully")
2574 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2575 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2576 int32(onuID),
2577 int32(uniID),
2578 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002579 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08002580 }
2581 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002582}
2583
salmansiddiqui7ac62132019-08-22 03:58:50 +00002584func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2585 if MeterID == 0 { // This should never happen
Thomas Lee S94109f12020-03-03 16:39:29 +05302586 return "", olterrors.NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002587 }
2588 if Dir == tp_pb.Direction_UPSTREAM {
2589 return "upstream", nil
2590 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2591 return "downstream", nil
2592 }
2593 return "", nil
2594}
2595
npujarec5762e2020-01-01 14:08:48 +05302596func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002597 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2598 TpID uint32, uni string) {
2599 var gemPort uint32
2600 intfID := args[IntfID]
2601 onuID := args[OnuID]
2602 uniID := args[UniID]
2603 portNo := args[PortNo]
2604 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002605 if ipProto, ok := classifierInfo[IPProto]; ok {
2606 if ipProto.(uint32) == IPProtoDhcp {
2607 log.Info("Adding DHCP flow")
2608 if pcp, ok := classifierInfo[VlanPcp]; ok {
2609 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2610 tp_pb.Direction_UPSTREAM,
2611 pcp.(uint32))
2612 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302613 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002614 } else {
2615 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302616 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002617 }
2618
2619 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002620 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2621 if pcp, ok := classifierInfo[VlanPcp]; ok {
2622 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2623 tp_pb.Direction_UPSTREAM,
2624 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302625 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002626 } else {
2627 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302628 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002629 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002630 } else {
2631 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2632 return
2633 }
2634 } else if ethType, ok := classifierInfo[EthType]; ok {
2635 if ethType.(uint32) == EapEthType {
2636 log.Info("Adding EAPOL flow")
2637 var vlanID uint32
2638 if val, ok := classifierInfo[VlanVid]; ok {
2639 vlanID = (val.(uint32)) & VlanvIDMask
2640 } else {
2641 vlanID = DefaultMgmtVlan
2642 }
2643 if pcp, ok := classifierInfo[VlanPcp]; ok {
2644 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2645 tp_pb.Direction_UPSTREAM,
2646 pcp.(uint32))
2647
Girish Gowdrafae935c2020-02-17 19:21:44 +05302648 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002649 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302650 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002651 }
2652 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002653 } else if _, ok := actionInfo[PushVlan]; ok {
2654 log.Info("Adding upstream data rule")
2655 if pcp, ok := classifierInfo[VlanPcp]; ok {
2656 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2657 tp_pb.Direction_UPSTREAM,
2658 pcp.(uint32))
2659 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302660 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002661 } else {
2662 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302663 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002664 }
2665 } else if _, ok := actionInfo[PopVlan]; ok {
2666 log.Info("Adding Downstream data rule")
2667 if pcp, ok := classifierInfo[VlanPcp]; ok {
2668 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002669 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002670 pcp.(uint32))
2671 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302672 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002673 } else {
2674 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302675 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002676 }
2677 } else {
2678 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2679 return
2680 }
2681 // Send Techprofile download event to child device in go routine as it takes time
2682 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2683}
2684
Gamze Abakafee36392019-10-03 11:17:24 +00002685func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2686 flowIDList := f.flowsUsedByGemPort[gemPK]
2687 if len(flowIDList) > 1 {
2688 return true
2689 }
2690 return false
2691}
2692
npujarec5762e2020-01-01 14:08:48 +05302693func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2694 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002695 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2696 for _, currentGemPort := range currentGemPorts {
2697 for _, tpGemPort := range tpGemPorts {
2698 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2699 return true, currentGemPort
2700 }
2701 }
2702 }
Girish Gowdra54934262019-11-13 14:19:55 +05302703 if tpInst.InstanceCtrl.Onu == "single-instance" {
2704 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302705 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2706 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302707
2708 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2709 // still be used on other uni ports.
2710 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2711 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302712 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302713 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302714 for i := 0; i < len(tpInstances); i++ {
2715 tpI := tpInstances[i]
2716 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302717 for _, tpGemPort := range tpGemPorts {
2718 if tpGemPort.GemportID != gemPortID {
2719 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2720 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302721 }
2722 }
2723 }
2724 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302725 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002726 return false, 0
2727}
2728
salmansiddiqui7ac62132019-08-22 03:58:50 +00002729func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002730 for _, field := range flows.GetOfbFields(flow) {
2731 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002732 classifierInfo[EthType] = field.GetEthType()
2733 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002734 } else if field.Type == flows.ETH_DST {
2735 classifierInfo[EthDst] = field.GetEthDst()
2736 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002737 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002738 classifierInfo[IPProto] = field.GetIpProto()
2739 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002740 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002741 classifierInfo[InPort] = field.GetPort()
2742 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002743 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302744 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002745 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002746 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002747 classifierInfo[VlanPcp] = field.GetVlanPcp()
2748 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002749 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002750 classifierInfo[UDPDst] = field.GetUdpDst()
2751 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002752 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002753 classifierInfo[UDPSrc] = field.GetUdpSrc()
2754 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002755 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002756 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2757 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002758 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002759 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2760 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002761 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002762 classifierInfo[Metadata] = field.GetTableMetadata()
2763 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002764 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002765 classifierInfo[TunnelID] = field.GetTunnelId()
2766 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2767 } else {
2768 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2769 return
2770 }
2771 }
2772}
2773
2774func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002775 for _, action := range flows.GetActions(flow) {
2776 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002777 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002778 actionInfo[Output] = out.GetPort()
2779 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002780 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00002781 return olterrors.NewErrInvalidValue(log.Fields{"output-port": nil}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002782 }
Scott Baker355d1742019-10-24 10:57:52 -07002783 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002784 actionInfo[PopVlan] = true
2785 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002786 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002787 if out := action.GetPush(); out != nil {
2788 if tpid := out.GetEthertype(); tpid != 0x8100 {
2789 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2790 } else {
2791 actionInfo[PushVlan] = true
2792 actionInfo[TPID] = tpid
2793 log.Debugw("action-type-push-vlan",
2794 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2795 }
2796 }
Scott Baker355d1742019-10-24 10:57:52 -07002797 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002798 if out := action.GetSetField(); out != nil {
2799 if field := out.GetField(); field != nil {
2800 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
Girish Kumarf26e4882020-03-05 06:49:10 +00002801 return olterrors.NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002802 }
2803 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002804 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002805 }
2806 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002807 } else if action.Type == flows.GROUP {
2808 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002809 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00002810 return olterrors.NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002811 }
2812 }
2813 return nil
2814}
2815
Esin Karamanccb714b2019-11-29 15:02:06 +00002816func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2817 if ofbField := field.GetOfbField(); ofbField != nil {
2818 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2819 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2820 actionInfo[VlanVid] = vlan & 0xfff
2821 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2822 } else {
2823 log.Error("No Invalid vlan id in set vlan-vid action")
2824 }
2825 } else {
2826 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2827 }
2828 }
2829}
2830
2831func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2832 if action.GetGroup() == nil {
2833 log.Warn("No group entry found in the group action")
2834 } else {
2835 actionInfo[GroupID] = action.GetGroup().GroupId
2836 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2837 }
2838}
2839
salmansiddiqui7ac62132019-08-22 03:58:50 +00002840func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002841 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002842 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2843 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2844 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002845 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002846 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002847 log.Debugw("upstream pon-to-controller-flow,inport-in-tunnelid", log.Fields{"newInPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002848 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302849 return olterrors.NewErrNotFound("child-in-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002850 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
Girish Kumarf26e4882020-03-05 06:49:10 +00002851 "flow": flow}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002852 }
2853 }
2854 } else {
2855 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2856 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002857 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002858 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002859 actionInfo[Output] = uniPort
2860 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[Output].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002861 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302862 return olterrors.NewErrNotFound("out-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002863 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
Girish Kumarf26e4882020-03-05 06:49:10 +00002864 "flow": flow}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002865 }
2866 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2867 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002868 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002869 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002870 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2871 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002872 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302873 return olterrors.NewErrNotFound("nni-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002874 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2875 "in-port": classifierInfo[InPort].(uint32),
2876 "out-port": actionInfo[Output].(uint32),
Girish Kumarf26e4882020-03-05 06:49:10 +00002877 "flow": flow}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002878 }
2879 }
2880 }
2881 return nil
2882}
Gamze Abakafee36392019-10-03 11:17:24 +00002883
Chaitrashree G S90a17952019-11-14 21:51:21 -05002884func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002885 /* Metadata 8 bytes:
2886 Most Significant 2 Bytes = Inner VLAN
2887 Next 2 Bytes = Tech Profile ID(TPID)
2888 Least Significant 4 Bytes = Port ID
2889 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2890 subscriber related flows.
2891 */
2892 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2893 if metadata == 0 {
Girish Kumarf26e4882020-03-05 06:49:10 +00002894 return 0, olterrors.NewErrNotFound("metadata", log.Fields{"flow": flow}, nil)
Gamze Abakafee36392019-10-03 11:17:24 +00002895 }
2896 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002897 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002898}
2899
2900func appendUnique(slice []uint32, item uint32) []uint32 {
2901 for _, sliceElement := range slice {
2902 if sliceElement == item {
2903 return slice
2904 }
2905 }
2906 return append(slice, item)
2907}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302908
2909// getNniIntfID gets nni intf id from the flow classifier/action
2910func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2911
2912 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2913 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002914 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2915 if err != nil {
2916 log.Debugw("invalid-action-port-number",
2917 log.Fields{
2918 "port-number": action[Output].(uint32),
2919 "error": err})
2920 return uint32(0), err
2921 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302922 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2923 return intfID, nil
2924 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002925 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2926 if err != nil {
2927 log.Debugw("invalid-classifier-port-number",
2928 log.Fields{
2929 "port-number": action[Output].(uint32),
2930 "error": err})
2931 return uint32(0), err
2932 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302933 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2934 return intfID, nil
2935 }
2936 return uint32(0), nil
2937}
2938
2939// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302940func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302941 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2942
2943 f.lockCache.Lock()
2944 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002945 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302946 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002947 if lookupGemPort == gemPort {
2948 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2949 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2950 return
2951 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302952 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002953 f.packetInGemPort[pktInkey] = gemPort
2954
npujarec5762e2020-01-01 14:08:48 +05302955 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002956 log.Debugw("pktin key not found in local cache or value is different. updating cache and kv store", log.Fields{"pktinkey": pktInkey, "gem": gemPort})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302957 return
2958}
2959
2960// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302961func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302962
2963 f.lockCache.Lock()
2964 defer f.lockCache.Unlock()
2965 onugem := f.onuGemInfo[intfID]
2966 for idx, onu := range onugem {
2967 if onu.OnuID == onuID {
2968 for _, uni := range onu.UniPorts {
2969 if uni == portNum {
2970 log.Debugw("uni already in cache, no need to update cache and kv store",
2971 log.Fields{"uni": portNum})
2972 return
2973 }
2974 }
2975 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2976 f.onuGemInfo[intfID] = onugem
2977 }
2978 }
npujarec5762e2020-01-01 14:08:48 +05302979 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302980}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302981
npujarec5762e2020-01-01 14:08:48 +05302982func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2983 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302984 if err != nil {
2985 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2986 return
2987 }
2988 for gem, FlowIDs := range flowIDsList {
2989 gemPK := gemPortKey{intf, uint32(gem)}
2990 f.flowsUsedByGemPort[gemPK] = FlowIDs
2991 }
2992 return
2993}
Esin Karamanccb714b2019-11-29 15:02:06 +00002994
2995//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2996//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302997func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2998 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002999 if err != nil {
3000 log.Error("Failed to get pon interface to multicast queue map")
3001 return
3002 }
3003 for intf, queueInfo := range storedMulticastQueueMap {
3004 q := queueInfoBrief{
3005 gemPortID: queueInfo[0],
3006 servicePriority: queueInfo[1],
3007 }
3008 f.interfaceToMcastQueueMap[intf] = &q
3009 }
3010}
3011
3012//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
3013//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
3014//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05303015func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
3016 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00003017 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00003018 return nil, false, olterrors.NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00003019 }
3020 if exists {
3021 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3022 }
3023 return nil, exists, nil
3024}
3025
3026func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3027 groupDesc := ofp.OfpGroupDesc{
3028 Type: ofp.OfpGroupType_OFPGT_ALL,
3029 GroupId: groupID,
3030 }
3031 groupEntry := ofp.OfpGroupEntry{
3032 Desc: &groupDesc,
3033 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003034 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003035 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003036 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003037 bucket := ofp.OfpBucket{
3038 Actions: acts,
3039 }
3040 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003041 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003042 return &groupEntry
3043}