blob: e29eb0e955cd6e19c26d8db9c1e3bb6449a39a08 [file] [log] [blame]
manikkaraj kbf256be2019-03-25 00:13:48 +05301/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Scott Bakerdbd960e2020-02-28 08:57:51 -080017//Package core provides the utility for olt devices, flows and statistics
18package core
manikkaraj kbf256be2019-03-25 00:13:48 +053019
20import (
21 "context"
22 "crypto/md5"
Matteo Scandolo6056e822019-11-13 14:05:29 -080023 "encoding/hex"
manikkaraj kbf256be2019-03-25 00:13:48 +053024 "encoding/json"
manikkaraj kbf256be2019-03-25 00:13:48 +053025 "fmt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040026 "math/big"
Girish Gowdrafae935c2020-02-17 19:21:44 +053027 "strings"
William Kurkian740a09c2019-10-23 17:07:38 -040028 "sync"
Girish Gowdra3d633032019-12-10 16:37:05 +053029 "time"
Manikkaraj kb1d51442019-07-23 10:41:02 -040030
Esin Karamanccb714b2019-11-29 15:02:06 +000031 "github.com/opencord/voltha-lib-go/v3/pkg/flows"
32 "github.com/opencord/voltha-lib-go/v3/pkg/log"
33 tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
Scott Bakerdbd960e2020-02-28 08:57:51 -080034 rsrcMgr "github.com/opencord/voltha-openolt-adapter/internal/pkg/resourcemanager"
Esin Karamanccb714b2019-11-29 15:02:06 +000035 "github.com/opencord/voltha-protos/v3/go/common"
36 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
37 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
38 openoltpb2 "github.com/opencord/voltha-protos/v3/go/openolt"
39 tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
40 "github.com/opencord/voltha-protos/v3/go/voltha"
Chaitrashree G S579fe732019-08-20 20:50:47 -040041
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040042 //deepcopy "github.com/getlantern/deepcopy"
Girish Gowdra3d633032019-12-10 16:37:05 +053043 "github.com/EagleChen/mapmutex"
Thomas Lee S94109f12020-03-03 16:39:29 +053044 "github.com/opencord/voltha-openolt-adapter/internal/pkg/olterrors"
Daniele Rossi22db98e2019-07-11 11:50:00 +000045 "google.golang.org/grpc/codes"
46 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053047)
48
49const (
50 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053051
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070052 //HsiaFlow flow category
53 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053054
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070055 //EapolFlow flow category
56 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053057
Manikkaraj kb1d51442019-07-23 10:41:02 -040058 //DhcpFlow flow category
59 DhcpFlow = "DHCP_FLOW"
60
Esin Karamanccb714b2019-11-29 15:02:06 +000061 //MulticastFlow flow category
62 MulticastFlow = "MULTICAST_FLOW"
63
Esin Karamanae41e2b2019-12-17 18:13:13 +000064 //IgmpFlow flow category
65 IgmpFlow = "IGMP_FLOW"
66
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070067 //IPProtoDhcp flow category
68 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053069
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070070 //IPProtoIgmp flow category
71 IPProtoIgmp = 2
72
73 //EapEthType eapethtype value
74 EapEthType = 0x888e
75 //LldpEthType lldp ethtype value
76 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000077 //IPv4EthType IPv4 ethernet type value
78 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070079
80 //IgmpProto proto value
81 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053082
Andrea Campanella7acc0b92020-02-14 09:20:49 +010083 //ReservedVlan Transparent Vlan (Masked Vlan, VLAN_ANY in ONOS Flows)
84 ReservedVlan = 4096
Harsh Awasthiea45af72019-08-26 02:39:00 -040085
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070086 //DefaultMgmtVlan default vlan value
87 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053088
manikkaraj kbf256be2019-03-25 00:13:48 +053089 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070090
David K. Bainbridge82efc492019-09-04 09:57:11 -070091 //Upstream constant
92 Upstream = "upstream"
93 //Downstream constant
94 Downstream = "downstream"
Esin Karamanccb714b2019-11-29 15:02:06 +000095 //Multicast constant
96 Multicast = "multicast"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070097 //PacketTagType constant
98 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -070099 //Untagged constant
100 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700101 //SingleTag constant
102 SingleTag = "single_tag"
103 //DoubleTag constant
104 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530105
106 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700107
108 //EthType constant
109 EthType = "eth_type"
Esin Karamanccb714b2019-11-29 15:02:06 +0000110 //EthDst constant
111 EthDst = "eth_dst"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700112 //TPID constant
113 TPID = "tpid"
114 //IPProto constant
115 IPProto = "ip_proto"
116 //InPort constant
117 InPort = "in_port"
118 //VlanVid constant
119 VlanVid = "vlan_vid"
120 //VlanPcp constant
121 VlanPcp = "vlan_pcp"
122
123 //UDPDst constant
124 UDPDst = "udp_dst"
125 //UDPSrc constant
126 UDPSrc = "udp_src"
127 //Ipv4Dst constant
128 Ipv4Dst = "ipv4_dst"
129 //Ipv4Src constant
130 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700131 //Metadata constant
132 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700133 //TunnelID constant
134 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700135 //Output constant
136 Output = "output"
Esin Karamanccb714b2019-11-29 15:02:06 +0000137 //GroupID constant
138 GroupID = "group_id"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700139 // Actions
140
141 //PopVlan constant
142 PopVlan = "pop_vlan"
143 //PushVlan constant
144 PushVlan = "push_vlan"
145 //TrapToHost constant
146 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400147 //MaxMeterBand constant
148 MaxMeterBand = 2
149 //VlanPCPMask contant
150 VlanPCPMask = 0xFF
151 //VlanvIDMask constant
152 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000153 //IntfID constant
154 IntfID = "intfId"
155 //OnuID constant
156 OnuID = "onuId"
157 //UniID constant
158 UniID = "uniId"
159 //PortNo constant
160 PortNo = "portNo"
161 //AllocID constant
162 AllocID = "allocId"
Esin Karamanccb714b2019-11-29 15:02:06 +0000163
164 //NoneOnuID constant
165 NoneOnuID = -1
166 //NoneUniID constant
167 NoneUniID = -1
168 //NoneGemPortID constant
169 NoneGemPortID = -1
Girish Gowdrafae935c2020-02-17 19:21:44 +0530170
171 // BinaryStringPrefix is binary string prefix
172 BinaryStringPrefix = "0b"
173 // BinaryBit1 is binary bit 1 expressed as a character
174 BinaryBit1 = '1'
manikkaraj kbf256be2019-03-25 00:13:48 +0530175)
176
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400177type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700178 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400179 gemPort uint32
180}
181
Girish Gowdra3d633032019-12-10 16:37:05 +0530182type pendingFlowDeleteKey struct {
183 intfID uint32
184 onuID uint32
185 uniID uint32
186}
187
188type tpLockKey struct {
189 intfID uint32
190 onuID uint32
191 uniID uint32
192}
193
Gamze Abakafee36392019-10-03 11:17:24 +0000194type schedQueue struct {
195 direction tp_pb.Direction
196 intfID uint32
197 onuID uint32
198 uniID uint32
199 tpID uint32
200 uniPort uint32
201 tpInst *tp.TechProfile
202 meterID uint32
203 flowMetadata *voltha.FlowMetadata
204}
205
Esin Karamanccb714b2019-11-29 15:02:06 +0000206type queueInfoBrief struct {
207 gemPortID uint32
208 servicePriority uint32
209}
210
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700211//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530212type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000213 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000214 deviceHandler *DeviceHandler
215 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000216 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530217 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
218 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
219 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
220 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530221 pendingFlowDelete sync.Map
222 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
Esin Karamanccb714b2019-11-29 15:02:06 +0000223 perUserFlowHandleLock *mapmutex.Mutex
224 interfaceToMcastQueueMap map[uint32]*queueInfoBrief /*pon interface -> multicast queue map. Required to assign GEM to a bucket during group population*/
manikkaraj kbf256be2019-03-25 00:13:48 +0530225}
226
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700227//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
npujarec5762e2020-01-01 14:08:48 +0530228func NewFlowManager(ctx context.Context, dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530229 log.Info("Initializing flow manager")
230 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530231 var err error
232 var idx uint32
233
manikkaraj kbf256be2019-03-25 00:13:48 +0530234 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530235 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000236 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530237 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530238 log.Error("Error while populating tech profile mgr\n")
239 return nil
240 }
William Kurkian740a09c2019-10-23 17:07:38 -0400241 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530242 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
243 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
244 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
245 ponPorts := rMgr.DevInfo.GetPonPorts()
246 //Load the onugem info cache from kv store on flowmanager start
247 for idx = 0; idx < ponPorts; idx++ {
npujarec5762e2020-01-01 14:08:48 +0530248 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(ctx, idx); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530249 log.Error("Failed to load onu gem info cache")
250 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530251 //Load flowID list per gem map per interface from the kvstore.
npujarec5762e2020-01-01 14:08:48 +0530252 flowMgr.loadFlowIDlistForGem(ctx, idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530253 }
254 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530255 flowMgr.pendingFlowDelete = sync.Map{}
256 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
Esin Karamanccb714b2019-11-29 15:02:06 +0000257 flowMgr.interfaceToMcastQueueMap = make(map[uint32]*queueInfoBrief)
258 //load interface to multicast queue map from kv store
npujarec5762e2020-01-01 14:08:48 +0530259 flowMgr.loadInterfaceToMulticastQueueMap(ctx)
manikkaraj kbf256be2019-03-25 00:13:48 +0530260 log.Info("Initialization of flow manager success!!")
261 return &flowMgr
262}
263
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700264func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700265 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400266 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700267 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700268 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400269 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700270 return uint64(flowID), nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000271 } else if direction == Multicast {
272 log.Debug("multicast flow, shifting id")
273 return 0x2<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400274 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +0530275 return 0, olterrors.NewErrInvalidValue(log.Fields{"direction": direction}, nil).Log()
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400276 }
277}
278
npujarec5762e2020-01-01 14:08:48 +0530279func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400280 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700281 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000282 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
283 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
284 if !ok {
285 flowIDList = []uint32{deviceFlow.FlowId}
286 }
287 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
288 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530289 // update the flowids for a gem to the KVstore
npujarec5762e2020-01-01 14:08:48 +0530290 f.resourceMgr.UpdateFlowIDsForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400291}
292
npujarec5762e2020-01-01 14:08:48 +0530293func (f *OpenOltFlowMgr) divideAndAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000294 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
295 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000296 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530297 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400298 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530299
Manikkaraj kb1d51442019-07-23 10:41:02 -0400300 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000301 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400302 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
303 // is because the flow is an NNI flow and there would be no onu resources associated with it
304 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400305 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400306 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530307 return
308 }
309
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530310 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400311 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530312
313 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
314 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
npujarec5762e2020-01-01 14:08:48 +0530315 allocID, gemPorts, TpInst = f.createTcontGemports(ctx, intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +0530316 if allocID == 0 || gemPorts == nil || TpInst == nil {
317 log.Error("alloc-id-gem-ports-tp-unavailable")
318 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
319 return
320 }
321 args := make(map[string]uint32)
322 args[IntfID] = intfID
323 args[OnuID] = onuID
324 args[UniID] = uniID
325 args[PortNo] = portNo
326 args[AllocID] = allocID
327
328 /* Flows can be added specific to gemport if p-bits are received.
329 * If no pbit mentioned then adding flows for all gemports
330 */
npujarec5762e2020-01-01 14:08:48 +0530331 f.checkAndAddFlow(ctx, args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
Girish Gowdra3d633032019-12-10 16:37:05 +0530332 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
333 } else {
334 log.Errorw("failed to acquire per user flow handle lock",
335 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400336 return
337 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530338}
339
salmansiddiqui7ac62132019-08-22 03:58:50 +0000340// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530341func (f *OpenOltFlowMgr) CreateSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400342
Gamze Abakafee36392019-10-03 11:17:24 +0000343 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
344 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
345 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400346
Gamze Abakafee36392019-10-03 11:17:24 +0000347 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000348 if err != nil {
349 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400350 }
351
352 /* Lets make a simple assumption that if the meter-id is present on the KV store,
353 * then the scheduler and queues configuration is applied on the OLT device
354 * in the given direction.
355 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000356
Manikkaraj kb1d51442019-07-23 10:41:02 -0400357 var SchedCfg *tp_pb.SchedulerConfig
npujarec5762e2020-01-01 14:08:48 +0530358 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400359 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000360 log.Error("Failed to get meter for intf %d, onuid %d, uniid %d", sq.intfID, sq.onuID, sq.uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400361 return err
362 }
363 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000364 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400365 log.Debug("Scheduler already created for upstream")
366 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400367 }
Thomas Lee S94109f12020-03-03 16:39:29 +0530368 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800369 "unsupported": "meter-id",
370 "kv-store-meter-id": KvStoreMeter.MeterId,
371 "meter-id-in-flow": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400372 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000373
Gamze Abakafee36392019-10-03 11:17:24 +0000374 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000375
Gamze Abakafee36392019-10-03 11:17:24 +0000376 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000377 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000378 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000379 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400380 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000381
382 if err != nil {
383 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
384 return err
385 }
386
Manikkaraj kb1d51442019-07-23 10:41:02 -0400387 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000388 if sq.flowMetadata != nil {
389 for _, meter := range sq.flowMetadata.Meters {
390 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400391 meterConfig = meter
392 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
393 break
394 }
395 }
396 } else {
397 log.Error("Flow-metadata-is-not-present-in-flow")
398 }
399 if meterConfig == nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530400 return olterrors.NewErrNotFound("meterbands", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800401 "reason": "Could-not-get-meterbands-from-flowMetadata",
402 "flow-metadata": sq.flowMetadata,
403 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400404 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000405 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
Thomas Lee S94109f12020-03-03 16:39:29 +0530406 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800407 "reason": "Invalid-number-of-bands-in-meter",
408 "meterband-count": len(meterConfig.Bands),
409 "metabands": meterConfig.Bands,
410 "meter-id": sq.meterID}, nil).Log()
Manikkaraj kb1d51442019-07-23 10:41:02 -0400411 }
412 cir := meterConfig.Bands[0].Rate
413 cbs := meterConfig.Bands[0].BurstSize
414 eir := meterConfig.Bands[1].Rate
415 ebs := meterConfig.Bands[1].BurstSize
416 pir := cir + eir
417 pbs := cbs + ebs
418 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
419
Gamze Abakafee36392019-10-03 11:17:24 +0000420 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400421
npujarec5762e2020-01-01 14:08:48 +0530422 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000423 log.Errorw("Failed to push traffic scheduler and queues to device", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400424 return err
425 }
426
salmansiddiqui7ac62132019-08-22 03:58:50 +0000427 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400428 * store the meter id on the KV store, for further reference.
429 */
npujarec5762e2020-01-01 14:08:48 +0530430 if err := f.resourceMgr.UpdateMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID, meterConfig); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000431 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400432 return err
433 }
434 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
435 "Meter": meterConfig})
436 return nil
437}
438
npujarec5762e2020-01-01 14:08:48 +0530439func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000440
441 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
442
443 if err != nil {
444 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
445 return err
446 }
447
448 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530449 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000450 IntfId: sq.intfID, OnuId: sq.onuID,
451 UniId: sq.uniID, PortNo: sq.uniPort,
452 TrafficScheds: TrafficSched}); err != nil {
453 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
454 return err
455 }
456
457 // On receiving the CreateTrafficQueues request, the driver should create corresponding
458 // downstream queues.
459 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530460 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000461 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
462 UniId: sq.uniID, PortNo: sq.uniPort,
463 TrafficQueues: trafficQueues}); err != nil {
464 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
465 return err
466 }
467
Esin Karamanccb714b2019-11-29 15:02:06 +0000468 if sq.direction == tp_pb.Direction_DOWNSTREAM {
469 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
470 if len(multicastTrafficQueues) > 0 {
471 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
472 //assumed that there is only one queue per PON for the multicast service
473 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
474 //just put it in interfaceToMcastQueueMap to use for building group members
475 multicastQueuePerPonPort := multicastTrafficQueues[0]
476 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
477 gemPortID: multicastQueuePerPonPort.GemportId,
478 servicePriority: multicastQueuePerPonPort.Priority,
479 }
480 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530481 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000482 multicastQueuePerPonPort.GemportId,
483 multicastQueuePerPonPort.Priority)
484 }
485 }
486 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000487 return nil
488}
489
salmansiddiqui7ac62132019-08-22 03:58:50 +0000490// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530491func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400492
493 var Direction string
494 var SchedCfg *tp_pb.SchedulerConfig
495 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000496 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
497 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
498 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000499 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400500 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000501 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000502 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400503 Direction = "downstream"
504 }
505
Girish Kumar8f73fe02019-12-09 13:19:37 +0000506 if err != nil {
507 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
508 return err
509 }
510
npujarec5762e2020-01-01 14:08:48 +0530511 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400512 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000513 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400514 return err
515 }
516 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000517 log.Debugw("No-meter-has-been-installed-yet", log.Fields{"direction": Direction, "IntfID": sq.intfID, "OnuID": sq.onuID, "UniID": sq.uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400518 return nil
519 }
520 cir := KVStoreMeter.Bands[0].Rate
521 cbs := KVStoreMeter.Bands[0].BurstSize
522 eir := KVStoreMeter.Bands[1].Rate
523 ebs := KVStoreMeter.Bands[1].BurstSize
524 pir := cir + eir
525 pbs := cbs + ebs
526
527 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
528
Gamze Abakafee36392019-10-03 11:17:24 +0000529 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000530
531 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
532 if err != nil {
533 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
534 return err
535 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400536
npujarec5762e2020-01-01 14:08:48 +0530537 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000538 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
539 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400540 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000541 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400542 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400543 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000544 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530545 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000546 IntfId: sq.intfID, OnuId: sq.onuID,
547 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400548 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000549 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400550 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400551 }
552
salmansiddiqui7ac62132019-08-22 03:58:50 +0000553 log.Debug("Removed traffic schedulers successfully")
554
555 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400556 * delete the meter id on the KV store.
557 */
npujarec5762e2020-01-01 14:08:48 +0530558 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400559 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000560 log.Errorf("Failed to remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000561 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400562 }
563 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
564 return err
565}
566
Gamze Abakafee36392019-10-03 11:17:24 +0000567// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530568func (f *OpenOltFlowMgr) createTcontGemports(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uni string, uniPort uint32, TpID uint32, UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) (uint32, []uint32, *tp.TechProfile) {
Gamze Abakafee36392019-10-03 11:17:24 +0000569 var allocIDs []uint32
570 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530571 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530572 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000573 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000574
npujarec5762e2020-01-01 14:08:48 +0530575 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
576 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400577
578 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530579
580 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
581
Manikkaraj kb1d51442019-07-23 10:41:02 -0400582 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530583 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000584 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530585 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530586 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000587 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530588 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000589 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000590 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530591 }
npujarec5762e2020-01-01 14:08:48 +0530592 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530593 } else {
594 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530595 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530596 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400597 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000598 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
599 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530600 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400601 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000602 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400603 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530604 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400605 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000606 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
607 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530608 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400609 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000610 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400611 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530612 }
Gamze Abakafee36392019-10-03 11:17:24 +0000613
614 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000615 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000616 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400617 }
Gamze Abakafee36392019-10-03 11:17:24 +0000618
Girish Gowdra3d633032019-12-10 16:37:05 +0530619 if tpInstanceExists {
620 return allocID, gemPortIDs, techProfileInstance
621 }
622
623 allocIDs = appendUnique(allocIDs, allocID)
624 for _, gemPortID := range gemPortIDs {
625 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
626 }
627
Gamze Abakafee36392019-10-03 11:17:24 +0000628 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530629 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530630 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000631 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530632}
633
npujarec5762e2020-01-01 14:08:48 +0530634func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530635
636 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700637 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530638 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530639 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530640 log.Error("Errow while uploading allocID to KV store")
641 }
npujarec5762e2020-01-01 14:08:48 +0530642 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530643 log.Error("Errow while uploading GEMports to KV store")
644 }
npujarec5762e2020-01-01 14:08:48 +0530645 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530646 log.Error("Errow while uploading gemtopon map to KV store")
647 }
648 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400649 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530650 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400651 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530652}
653
654func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000655 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530656 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000657 for _, intfID := range techRange.IntfIds {
658 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400659 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000660 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530661 }
662 }
663 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400664 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
Thomas Lee S94109f12020-03-03 16:39:29 +0530665 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800666 "reason": "TP count does not match number of PON ports",
667 "tech-profile-count": tpCount,
668 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530669 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400670 log.Infow("Populated techprofile for ponports successfully",
671 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530672 return nil
673}
674
npujarec5762e2020-01-01 14:08:48 +0530675func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530676 portNo uint32, uplinkClassifier map[string]interface{},
677 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800678 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700679 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530680 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800681 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700682 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530683 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530684}
685
npujarec5762e2020-01-01 14:08:48 +0530686func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530687 portNo uint32, downlinkClassifier map[string]interface{},
688 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800689 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700690 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530691 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
692 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400693 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
694 if vlan, exists := downlinkClassifier[VlanVid]; exists {
695 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700696 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400697 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
698 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800699 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400700 }
701 }
702 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530703 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400704
Manikkaraj k884c1242019-04-11 16:26:42 +0530705 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700706 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400707 // vlan_vid is a uint32. must be type asserted as such or conversion fails
708 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530709 if ok {
710 downlinkAction[VlanVid] = dlClVid & 0xfff
711 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +0530712 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800713 "reason": "failed to convert VLANID classifier",
714 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530715 }
716
David K. Bainbridge794735f2020-02-11 21:01:37 -0800717 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700718 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530719}
720
npujarec5762e2020-01-01 14:08:48 +0530721func (f *OpenOltFlowMgr) addHSIAFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Manikkaraj k884c1242019-04-11 16:26:42 +0530722 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800723 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530724 /* One of the OLT platform (Broadcom BAL) requires that symmetric
725 flows require the same flow_id to be used across UL and DL.
726 Since HSIA flow is the only symmetric flow currently, we need to
727 re-use the flow_id across both direction. The 'flow_category'
728 takes priority over flow_cookie to find any available HSIA_FLOW
729 id for the ONU.
730 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700731 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
732 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530733 "logicalFlow": *logicalFlow})
Girish Gowdrafae935c2020-02-17 19:21:44 +0530734 var vlanPbit uint32 = 0xff // means no pbit
Manikkaraj kb1d51442019-07-23 10:41:02 -0400735 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000736 vlanPbit = classifier[VlanPcp].(uint32)
737 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800738 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +0530739 log.Debugw("pbit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400740 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700741 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530742 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800743 log.Debug("flow-already-exists")
744 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530745 }
npujarec5762e2020-01-01 14:08:48 +0530746 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530747 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530748 return olterrors.NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530749 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800750 classifierProto, err := makeOpenOltClassifierField(classifier)
751 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530752 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530753 }
754 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800755 actionProto, err := makeOpenOltActionField(action)
756 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530757 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530758 }
759 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800760 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530761 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530762 return olterrors.NewErrNotFound("nni-interface-id",
David K. Bainbridge794735f2020-02-11 21:01:37 -0800763 log.Fields{
764 "classifier": classifier,
765 "action": action,
766 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530767 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700768 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
769 OnuId: int32(onuID),
770 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000771 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530772 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700773 AllocId: int32(allocID),
774 NetworkIntfId: int32(networkIntfID),
775 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530776 Classifier: classifierProto,
777 Action: actionProto,
778 Priority: int32(logicalFlow.Priority),
779 Cookie: logicalFlow.Cookie,
780 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800781 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530782 return olterrors.NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530783 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800784 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
785 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
786 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
787 flow.OnuId,
788 flow.UniId,
789 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530790 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800791 }
792 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530793}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000794
David K. Bainbridge794735f2020-02-11 21:01:37 -0800795func (f *OpenOltFlowMgr) addDHCPTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{}, action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530796
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530797 networkIntfID, err := getNniIntfID(classifier, action)
798 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530799 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800800 "classifier": classifier,
801 "action": action},
802 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530803 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530804
805 // Clear the action map
806 for k := range action {
807 delete(action, k)
808 }
809
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700810 action[TrapToHost] = true
811 classifier[UDPSrc] = uint32(68)
812 classifier[UDPDst] = uint32(67)
813 classifier[PacketTagType] = SingleTag
814 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530815
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700816 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530817 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530818 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800819 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530820 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530821
David K. Bainbridge794735f2020-02-11 21:01:37 -0800822 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, DhcpFlow, 0 /*classifier[VLAN_PCP].(uint32)*/)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530823
824 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530825 return olterrors.NewErrNotFound("flow", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800826 "interface-id": intfID,
827 "gem-port": gemPortID,
828 "cookie": flowStoreCookie},
829 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530830 }
831
832 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
833
David K. Bainbridge794735f2020-02-11 21:01:37 -0800834 classifierProto, err := makeOpenOltClassifierField(classifier)
835 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530836 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530837 }
838 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800839 actionProto, err := makeOpenOltActionField(action)
840 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530841 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530842 }
843
David K. Bainbridge794735f2020-02-11 21:01:37 -0800844 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700845 OnuId: int32(onuID),
846 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530847 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700848 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700849 AllocId: int32(allocID),
850 NetworkIntfId: int32(networkIntfID),
851 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530852 Classifier: classifierProto,
853 Action: actionProto,
854 Priority: int32(logicalFlow.Priority),
855 Cookie: logicalFlow.Cookie,
856 PortNo: portNo}
857
David K. Bainbridge794735f2020-02-11 21:01:37 -0800858 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530859 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800860 }
861 log.Debug("DHCP UL flow added to device successfully")
862 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
863 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
864 dhcpFlow.OnuId,
865 dhcpFlow.UniId,
866 dhcpFlow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530867 return olterrors.NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530868 }
869
David K. Bainbridge794735f2020-02-11 21:01:37 -0800870 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530871}
872
Esin Karamanae41e2b2019-12-17 18:13:13 +0000873//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530874func (f *OpenOltFlowMgr) addIGMPTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -0800875 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
876 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000877}
878
879//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530880func (f *OpenOltFlowMgr) addUpstreamTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -0800881 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000882
883 networkIntfID, err := getNniIntfID(classifier, action)
884 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530885 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800886 "classifier": classifier,
887 "action": action},
888 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000889 }
890
891 // Clear the action map
892 for k := range action {
893 delete(action, k)
894 }
895
896 action[TrapToHost] = true
897 classifier[PacketTagType] = SingleTag
898 delete(classifier, VlanVid)
899
900 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530901 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800902 log.Debug("Flow-exists-not-re-adding")
903 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000904 }
905
npujarec5762e2020-01-01 14:08:48 +0530906 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, flowType, 0, 0 /*classifier[VLAN_PCP].(uint32)*/)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000907
908 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530909 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800910 "interface-id": intfID,
911 "oni-id": onuID,
912 "cookie": flowStoreCookie,
913 "flow-type": flowType},
914 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000915 }
916
917 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
918
David K. Bainbridge794735f2020-02-11 21:01:37 -0800919 classifierProto, err := makeOpenOltClassifierField(classifier)
920 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530921 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000922 }
923 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800924 actionProto, err := makeOpenOltActionField(action)
925 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530926 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000927 }
928
David K. Bainbridge794735f2020-02-11 21:01:37 -0800929 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000930 OnuId: int32(onuID),
931 UniId: int32(uniID),
932 FlowId: flowID,
933 FlowType: Upstream,
934 AllocId: int32(allocID),
935 NetworkIntfId: int32(networkIntfID),
936 GemportId: int32(gemPortID),
937 Classifier: classifierProto,
938 Action: actionProto,
939 Priority: int32(logicalFlow.Priority),
940 Cookie: logicalFlow.Cookie,
941 PortNo: portNo}
942
David K. Bainbridge794735f2020-02-11 21:01:37 -0800943 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530944 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800945 }
946 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000947
David K. Bainbridge794735f2020-02-11 21:01:37 -0800948 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
949 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
950 flow.OnuId,
951 flow.UniId,
952 flow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530953 return olterrors.NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000954 }
955
David K. Bainbridge794735f2020-02-11 21:01:37 -0800956 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000957}
958
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700959// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Girish Gowdrafae935c2020-02-17 19:21:44 +0530960func (f *OpenOltFlowMgr) addEAPOLFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{}, action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, vlanID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700961 log.Debugw("Adding EAPOL to device", log.Fields{"intfId": intfID, "onuId": onuID, "portNo": portNo, "allocId": allocID, "gemPortId": gemPortID, "vlanId": vlanID, "flow": logicalFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +0530962
963 uplinkClassifier := make(map[string]interface{})
964 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530965
manikkaraj kbf256be2019-03-25 00:13:48 +0530966 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700967 uplinkClassifier[EthType] = uint32(EapEthType)
968 uplinkClassifier[PacketTagType] = SingleTag
969 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530970 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700971 uplinkAction[TrapToHost] = true
972 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530973 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800974 log.Debug("Flow-exists-not-re-adding")
975 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530976 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530977 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530978 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530979 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530980 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800981 "interface-id": intfID,
982 "onu-id": onuID,
983 "coookie": flowStoreCookie},
984 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530985 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700986 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530987
David K. Bainbridge794735f2020-02-11 21:01:37 -0800988 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
989 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530990 return olterrors.NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530991 }
992 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800993 actionProto, err := makeOpenOltActionField(uplinkAction)
994 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530995 return olterrors.NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530996 }
997 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800998 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530999 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301000 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001001 "classifier": classifier,
1002 "action": action},
1003 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301004 }
1005
David K. Bainbridge794735f2020-02-11 21:01:37 -08001006 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001007 OnuId: int32(onuID),
1008 UniId: int32(uniID),
1009 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001010 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001011 AllocId: int32(allocID),
1012 NetworkIntfId: int32(networkIntfID),
1013 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301014 Classifier: classifierProto,
1015 Action: actionProto,
1016 Priority: int32(logicalFlow.Priority),
1017 Cookie: logicalFlow.Cookie,
1018 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001019 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301020 return olterrors.NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001021 }
1022 log.Debug("EAPOL UL flow added to device successfully")
1023 flowCategory := "EAPOL"
1024 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1025 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1026 upstreamFlow.OnuId,
1027 upstreamFlow.UniId,
1028 upstreamFlow.FlowId,
1029 /* lowCategory, */
1030 flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301031 return olterrors.NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301032 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301033
manikkaraj kbf256be2019-03-25 00:13:48 +05301034 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001035 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301036}
1037
David K. Bainbridge794735f2020-02-11 21:01:37 -08001038func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001039 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001040
1041 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1042 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1043 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
Andrea Campanella7acc0b92020-02-14 09:20:49 +01001044 if vlanID != ReservedVlan {
1045 vid := vlanID & VlanvIDMask
Harsh Awasthiea45af72019-08-26 02:39:00 -04001046 classifier.OVid = vid
1047 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301048 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001049 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1050 vid := uint32(metadata)
1051 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001052 classifier.IVid = vid
1053 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301054 }
Girish Gowdrafae935c2020-02-17 19:21:44 +05301055 // Use VlanPCPMask (0xff) to signify NO PCP. Else use valid PCP (0 to 7)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001056 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Girish Gowdrafae935c2020-02-17 19:21:44 +05301057 classifier.OPbits = vlanPcp
1058 } else {
1059 classifier.OPbits = VlanPCPMask
manikkaraj kbf256be2019-03-25 00:13:48 +05301060 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001061 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1062 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1063 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1064 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001065 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001066 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1067 classifier.PktTagType = pktTagType
1068
1069 switch pktTagType {
1070 case SingleTag:
1071 case DoubleTag:
1072 case Untagged:
1073 default:
Thomas Lee S94109f12020-03-03 16:39:29 +05301074 return nil, olterrors.NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301075 }
1076 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001077 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301078}
1079
David K. Bainbridge794735f2020-02-11 21:01:37 -08001080func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001081 var actionCmd openoltpb2.ActionCmd
1082 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301083 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001084 if _, ok := actionInfo[PopVlan]; ok {
1085 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301086 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001087 } else if _, ok := actionInfo[PushVlan]; ok {
1088 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301089 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001090 } else if _, ok := actionInfo[TrapToHost]; ok {
1091 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301092 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05301093 return nil, olterrors.NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301094 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001095 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301096}
1097
Manikkaraj kb1d51442019-07-23 10:41:02 -04001098func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1099 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301100}
1101
Gamze Abakafee36392019-10-03 11:17:24 +00001102// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301103func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1104 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001105 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001106 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301107 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +00001108 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
Girish Gowdra54934262019-11-13 14:19:55 +05301109 // return err
1110 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001111 }
1112 }
1113 return nil
1114}
1115
1116// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301117func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001118 if uniPortName == "" {
1119 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1120 }
npujarec5762e2020-01-01 14:08:48 +05301121 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001122 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1123 return err
1124 }
1125 return nil
1126}
1127
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001128func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301129 if len(classifier) == 0 { // should never happen
1130 log.Error("Invalid classfier object")
1131 return 0
1132 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301133 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301134 var jsonData []byte
1135 var flowString string
1136 var err error
1137 // TODO: Do we need to marshall ??
1138 if jsonData, err = json.Marshal(classifier); err != nil {
1139 log.Error("Failed to encode classifier")
1140 return 0
1141 }
1142 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001143 if gemPortID != 0 {
1144 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301145 }
1146 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001147 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301148 hash := big.NewInt(0)
1149 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301150 generatedHash := hash.Uint64()
1151 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1152 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301153}
1154
npujarec5762e2020-01-01 14:08:48 +05301155func (f *OpenOltFlowMgr) getUpdatedFlowInfo(ctx context.Context, flow *openoltpb2.Flow, flowStoreCookie uint64, flowCategory string, deviceFlowID uint32, logicalFlowID uint64) *[]rsrcMgr.FlowInfo {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301156 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001157 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001158 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1159 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1160 */
1161 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001162 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001163 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001164 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001165 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001166 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301167 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001168 if existingFlows != nil {
1169 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001170 //for _, f := range *existingFlows {
1171 // flows = append(flows, f)
1172 //}
1173 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001174 }
1175 log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
manikkaraj kbf256be2019-03-25 00:13:48 +05301176 return &flows
1177}
1178
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001179//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1180// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1181// var intfId uint32
1182// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1183// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1184// */
1185// if flow.AccessIntfId != -1 {
1186// intfId = uint32(flow.AccessIntfId)
1187// } else {
1188// intfId = uint32(flow.NetworkIntfId)
1189// }
1190// // Get existing flows matching flowid for given subscriber from KV store
1191// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1192// if existingFlows != nil {
1193// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1194// for _, f := range *existingFlows {
1195// flows = append(flows, f)
1196// }
1197// }
1198// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1199// return &flows
1200//}
1201
npujarec5762e2020-01-01 14:08:48 +05301202func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(ctx context.Context, intfID int32, onuID int32, uniID int32, flowID uint32, flows *[]rsrcMgr.FlowInfo) error {
manikkaraj k17652a72019-05-06 09:06:36 -04001203 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301204 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001205 log.Debug("Error while Storing flow into KV store")
1206 return err
1207 }
1208 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301209 return nil
1210}
1211
David K. Bainbridge794735f2020-02-11 21:01:37 -08001212func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001213
1214 var intfID uint32
1215 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1216 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1217 */
1218 if deviceFlow.AccessIntfId != -1 {
1219 intfID = uint32(deviceFlow.AccessIntfId)
1220 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001221 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001222 intfID = uint32(deviceFlow.NetworkIntfId)
1223 }
1224
manikkaraj kbf256be2019-03-25 00:13:48 +05301225 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1226 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001227
1228 st, _ := status.FromError(err)
1229 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001230 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001231 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301232 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001233
1234 if err != nil {
1235 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301236 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001237 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001238 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301239 if deviceFlow.GemportId != -1 {
1240 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301241 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301242 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301243 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001244 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001245}
1246
David K. Bainbridge794735f2020-02-11 21:01:37 -08001247func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001248 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1249 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1250 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001251 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1252 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1253 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001254 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001255 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001256 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001257 return err
serkant.uluderya245caba2019-09-24 23:15:29 -07001258
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001259 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001260 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001261 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301262}
1263
1264/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1265 //update core flows_proxy : flows_proxy.update('/', flows)
1266}
1267
1268func generateStoredId(flowId uint32, direction string)uint32{
1269
David K. Bainbridge82efc492019-09-04 09:57:11 -07001270 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301271 log.Debug("Upstream flow shifting flowid")
1272 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001273 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301274 log.Debug("Downstream flow not shifting flowid")
1275 return flowId
1276 }else{
1277 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1278 return flowId
1279 }
1280}
1281
1282*/
1283
David K. Bainbridge794735f2020-02-11 21:01:37 -08001284func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001285
1286 classifierInfo := make(map[string]interface{})
1287 actionInfo := make(map[string]interface{})
1288
1289 classifierInfo[EthType] = uint32(LldpEthType)
1290 classifierInfo[PacketTagType] = Untagged
1291 actionInfo[TrapToHost] = true
1292
1293 // LLDP flow is installed to trap LLDP packets on the NNI port.
1294 // We manage flow_id resource pool on per PON port basis.
1295 // Since this situation is tricky, as a hack, we pass the NNI port
1296 // index (network_intf_id) as PON port Index for the flow_id resource
1297 // pool. Also, there is no ONU Id available for trapping LLDP packets
1298 // on NNI port, use onu_id as -1 (invalid)
1299 // ****************** CAVEAT *******************
1300 // This logic works if the NNI Port Id falls within the same valid
1301 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1302 // we need to have a re-look at this.
1303 // *********************************************
1304
1305 var onuID = -1
1306 var uniID = -1
1307 var gemPortID = -1
1308
David K. Bainbridge794735f2020-02-11 21:01:37 -08001309 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1310 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301311 return olterrors.NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001312 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001313 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301314 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001315 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001316 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001317 }
npujarec5762e2020-01-01 14:08:48 +05301318 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001319
1320 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301321 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001322 "interface-id": networkInterfaceID,
1323 "onu-id": onuID,
1324 "uni-id": uniID,
1325 "gem-port-id": gemPortID,
1326 "cookie": flowStoreCookie},
1327 err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001328 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001329 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1330 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301331 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001332 }
1333 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001334 actionProto, err := makeOpenOltActionField(actionInfo)
1335 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301336 return olterrors.NewErrInvalidValue(log.Fields{"action": actionInfo}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001337 }
1338 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1339
1340 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1341 OnuId: int32(onuID), // OnuId not required
1342 UniId: int32(uniID), // UniId not used
1343 FlowId: flowID,
1344 FlowType: Downstream,
1345 NetworkIntfId: int32(networkInterfaceID),
1346 GemportId: int32(gemPortID),
1347 Classifier: classifierProto,
1348 Action: actionProto,
1349 Priority: int32(flow.Priority),
1350 Cookie: flow.Cookie,
1351 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001352 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301353 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Humera Kouser94d7a842019-08-25 19:04:32 -04001354 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001355 log.Debug("LLDP trap on NNI flow added to device successfully")
1356 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1357 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1358 int32(onuID),
1359 int32(uniID),
1360 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301361 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001362 }
1363 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301364}
1365
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301366func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001367 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1368}
1369
1370//getOnuChildDevice to fetch onu
1371func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1372 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1373 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001374 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1375 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301376 return nil, olterrors.NewErrNotFound("onu", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001377 "interface-id": parentPortNo,
1378 "onu-id": onuID},
1379 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301380 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301381 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1382 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301383}
1384
1385func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001386 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301387 return nil
1388}
1389
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001390func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1391 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301392}
1393
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001394func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001395 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001396 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001397 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001398 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001399}
1400
Girish Gowdra6b130582019-11-20 16:45:20 +05301401func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1402 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1403 if err != nil {
1404 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1405 return err
1406 }
1407
1408 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1409 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1410 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1411 delGemPortMsg,
1412 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1413 f.deviceHandler.deviceType,
1414 onuDevice.Type,
1415 onuDevice.Id,
1416 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1417 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1418 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1419 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1420 return sendErr
1421 }
1422 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1423 return nil
1424}
1425
1426func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1427 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1428 if err != nil {
1429 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1430 return err
1431 }
1432
1433 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1434 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1435 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1436 delTcontMsg,
1437 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1438 f.deviceHandler.deviceType,
1439 onuDevice.Type,
1440 onuDevice.Id,
1441 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1442 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1443 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1444 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1445 return sendErr
1446 }
1447 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1448 return nil
1449}
1450
Girish Gowdra3d633032019-12-10 16:37:05 +05301451func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1452 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1453 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1454 if val.(int) > 0 {
1455 pnFlDels := val.(int) - 1
1456 if pnFlDels > 0 {
1457 log.Debugw("flow delete succeeded, more pending",
1458 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1459 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1460 } else {
1461 log.Debugw("all pending flow deletes handled, removing entry from map",
1462 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1463 f.pendingFlowDelete.Delete(pnFlDelKey)
1464 }
1465 }
1466 } else {
1467 log.Debugw("no pending delete flows found",
1468 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1469
1470 }
1471
1472}
1473
Girish Gowdrac3037402020-01-22 20:29:53 +05301474// Once the gemport is released for a given onu, it also has to be cleared from local cache
1475// which was used for deriving the gemport->logicalPortNo during packet-in.
1476// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1477// is conveyed to ONOS during packet-in OF message.
1478func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1479 f.lockCache.Lock()
1480 defer f.lockCache.Unlock()
1481 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001482 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301483 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001484 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301485 // If the gemport is found, delete it from local cache.
1486 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001487 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1488 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301489 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001490 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301491 break
1492 }
1493 }
1494 break
1495 }
1496 }
1497}
1498
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301499//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301500func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301501 gemPortID int32, flowID uint32, flowDirection string,
1502 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001503
Chaitrashree G S90a17952019-11-14 21:51:21 -05001504 tpID, err := getTpIDFromFlow(flow)
1505 if err != nil {
1506 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1507 return err
1508 }
Gamze Abakafee36392019-10-03 11:17:24 +00001509
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001510 if len(updatedFlows) >= 0 {
1511 // There are still flows referencing the same flow_id.
1512 // So the flow should not be freed yet.
1513 // For ex: Case of HSIA where same flow is shared
1514 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301515 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001516 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301517 // Do this for subscriber flows only (not trap from NNI flows)
1518 if onuID != -1 && uniID != -1 {
1519 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1520 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1521 log.Debugw("creating entry for pending flow delete",
1522 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1523 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1524 } else {
1525 pnFlDels := val.(int) + 1
1526 log.Debugw("updating flow delete entry",
1527 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1528 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1529 }
1530
1531 defer f.deletePendingFlows(Intf, onuID, uniID)
1532 }
1533
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301534 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301535 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001536
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301537 uni := getUniPortPath(Intf, onuID, uniID)
1538 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001539 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301540 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001541 if err != nil { // This should not happen, something wrong in KV backend transaction
1542 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301543 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001544 }
1545 if techprofileInst == nil {
1546 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301547 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001548 }
1549
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301550 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001551 if f.isGemPortUsedByAnotherFlow(gemPK) {
1552 flowIDs := f.flowsUsedByGemPort[gemPK]
1553 for i, flowIDinMap := range flowIDs {
1554 if flowIDinMap == flowID {
1555 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301556 // everytime flowsUsedByGemPort cache is updated the same should be updated
1557 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001558 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301559 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001560 break
1561 }
1562 }
1563 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301564 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001565 }
Gamze Abakafee36392019-10-03 11:17:24 +00001566 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301567 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001568 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1569 // But it is anyway eventually removed later when the TechProfile is freed, so not a big issue for now.
npujarec5762e2020-01-01 14:08:48 +05301570 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301571 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001572 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301573 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1574 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001575 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301576 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1577 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001578 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301579 // Delete the gem port on the ONU.
1580 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1581 log.Errorw("error processing delete gem-port towards onu",
1582 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1583 }
Gamze Abakafee36392019-10-03 11:17:24 +00001584
npujarec5762e2020-01-01 14:08:48 +05301585 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001586 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301587 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1588 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1589 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1590 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1591 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301592 // Delete the TCONT on the ONU.
1593 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1594 log.Errorw("error processing delete tcont towards onu",
1595 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1596 }
Gamze Abakafee36392019-10-03 11:17:24 +00001597 }
1598 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001599 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301600 return nil
1601}
1602
David K. Bainbridge794735f2020-02-11 21:01:37 -08001603// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301604func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301605
1606 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001607
1608 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301609 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001610 return
1611 }
1612
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301613 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301614 classifierInfo := make(map[string]interface{})
1615
1616 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1617 if err != nil {
1618 log.Error(err)
1619 return
1620 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301621
David K. Bainbridge794735f2020-02-11 21:01:37 -08001622 onuID := int32(onu)
1623 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301624
1625 for _, field := range flows.GetOfbFields(flow) {
1626 if field.Type == flows.IP_PROTO {
1627 classifierInfo[IPProto] = field.GetIpProto()
1628 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1629 }
1630 }
1631 log.Debugw("Extracted access info from flow to be deleted",
1632 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1633
1634 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1635 onuID = -1
1636 uniID = -1
1637 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001638 Intf, err = IntfIDFromNniPortNum(inPort)
1639 if err != nil {
1640 log.Errorw("invalid-in-port-number",
1641 log.Fields{
1642 "port-number": inPort,
1643 "error": err})
1644 return
1645 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301646 }
npujarec5762e2020-01-01 14:08:48 +05301647 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001648 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301649 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301650 if flowInfo == nil {
1651 log.Debugw("No FlowInfo found found in KV store",
1652 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1653 return
1654 }
1655 updatedFlows = nil
1656 for _, flow := range *flowInfo {
1657 updatedFlows = append(updatedFlows, flow)
1658 }
1659
1660 for i, storedFlow := range updatedFlows {
1661 if flow.Id == storedFlow.LogicalFlowID {
1662 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1663 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001664 // DKB
1665 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1666 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1667 return
1668 }
1669 log.Debug("Flow removed from device successfully")
1670 //Remove the Flow from FlowInfo
1671 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1672 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1673 flowID, flowDirection, portNum, updatedFlows); err != nil {
1674 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301675 return
1676 }
1677 }
1678 }
1679 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001680}
1681
Esin Karamanccb714b2019-11-29 15:02:06 +00001682//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1683// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301684func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001685 classifierInfo := make(map[string]interface{})
1686 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301687 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001688
1689 if err != nil {
1690 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1691 return
1692 }
1693
David K. Bainbridge794735f2020-02-11 21:01:37 -08001694 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1695 if err != nil {
1696 // DKB
1697 log.Errorw("invalid-in-port-number",
1698 log.Fields{
1699 "port-number": inPort,
1700 "error": err})
1701 return
1702 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001703 var onuID = int32(NoneOnuID)
1704 var uniID = int32(NoneUniID)
1705 var flowID uint32
1706 var updatedFlows []rsrcMgr.FlowInfo
1707
npujarec5762e2020-01-01 14:08:48 +05301708 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001709
1710 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301711 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001712 if flowInfo == nil {
1713 log.Debugw("No multicast FlowInfo found in the KV store",
1714 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1715 continue
1716 }
1717 updatedFlows = nil
1718 for _, flow := range *flowInfo {
1719 updatedFlows = append(updatedFlows, flow)
1720 }
1721 for i, storedFlow := range updatedFlows {
1722 if flow.Id == storedFlow.LogicalFlowID {
1723 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1724 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1725 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001726 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1727 // DKB
1728 log.Errorw("failed-to-remove-multicast-flow",
1729 log.Fields{
1730 "flow-id": flow.Id,
1731 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001732 return
1733 }
1734 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1735 //Remove the Flow from FlowInfo
1736 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301737 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001738 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1739 return
1740 }
1741 //release flow id
1742 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301743 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001744 }
1745 }
1746 }
1747}
1748
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001749//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301750func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001751 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301752 var direction string
1753 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001754
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301755 for _, action := range flows.GetActions(flow) {
1756 if action.Type == flows.OUTPUT {
1757 if out := action.GetOutput(); out != nil {
1758 actionInfo[Output] = out.GetPort()
1759 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1760 } else {
1761 log.Error("Invalid output port in action")
1762 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001763 }
1764 }
1765 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001766
1767 if flows.HasGroup(flow) {
1768 direction = Multicast
1769 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301770 direction = Upstream
1771 } else {
1772 direction = Downstream
1773 }
npujarec5762e2020-01-01 14:08:48 +05301774 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301775
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001776 return
1777}
1778
Girish Gowdra3d633032019-12-10 16:37:05 +05301779func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1780 uniID uint32, ch chan bool) {
1781 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1782 for {
1783 select {
1784 case <-time.After(20 * time.Millisecond):
1785 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1786 log.Debug("pending flow deletes completed")
1787 ch <- true
1788 return
1789 }
1790 case <-ctx.Done():
1791 log.Error("flow delete wait handler routine canceled")
1792 return
1793 }
1794 }
1795}
1796
Esin Karamanae41e2b2019-12-17 18:13:13 +00001797//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1798func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1799 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1800 if ethType, ok := classifierInfo[EthType]; ok {
1801 if ethType.(uint32) == IPv4EthType {
1802 if ipProto, ok := classifierInfo[IPProto]; ok {
1803 if ipProto.(uint32) == IgmpProto {
1804 return true
1805 }
1806 }
1807 }
1808 }
1809 }
1810 return false
1811}
1812
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001813// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301814// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301815func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001816 classifierInfo := make(map[string]interface{})
1817 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001818 var UsMeterID uint32
1819 var DsMeterID uint32
1820
1821 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001822 formulateClassifierInfoFromFlow(classifierInfo, flow)
1823
1824 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1825 if err != nil {
1826 // Error logging is already done in the called function
1827 // So just return in case of error
1828 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301829 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001830
Esin Karamanccb714b2019-11-29 15:02:06 +00001831 if flows.HasGroup(flow) {
1832 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301833 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001834 return
1835 }
1836
manikkaraj k17652a72019-05-06 09:06:36 -04001837 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001838 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1839 if err != nil {
1840 // error if any, already logged in the called function
1841 return
manikkaraj k17652a72019-05-06 09:06:36 -04001842 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001843
David K. Bainbridge82efc492019-09-04 09:57:11 -07001844 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1845 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001846
Humera Kouser94d7a842019-08-25 19:04:32 -04001847 if ethType, ok := classifierInfo[EthType]; ok {
1848 if ethType.(uint32) == LldpEthType {
1849 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301850 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001851 return
1852 }
1853 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001854 if ipProto, ok := classifierInfo[IPProto]; ok {
1855 if ipProto.(uint32) == IPProtoDhcp {
1856 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301857 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001858 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301859 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001860 return
1861 }
1862 }
1863 }
1864 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001865 if isIgmpTrapDownstreamFlow(classifierInfo) {
1866 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301867 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001868 return
1869 }
A R Karthick1f85b802019-10-11 05:06:05 +00001870
1871 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301872 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001873
Chaitrashree G S90a17952019-11-14 21:51:21 -05001874 TpID, err := getTpIDFromFlow(flow)
1875 if err != nil {
1876 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1877 return
1878 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001879 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001880 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001881 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001882 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1883 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001884 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001885 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1886
1887 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301888
1889 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1890 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1891 log.Debugw("no pending flows found, going ahead with flow install", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301892 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301893 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301894 pendingFlowDelComplete := make(chan bool)
1895 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1896 select {
1897 case <-pendingFlowDelComplete:
1898 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301899 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301900
1901 case <-time.After(10 * time.Second):
1902 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1903 }
1904 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001905}
1906
Esin Karamanccb714b2019-11-29 15:02:06 +00001907// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001908func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001909 classifierInfo[PacketTagType] = DoubleTag
1910 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1911
npujarec5762e2020-01-01 14:08:48 +05301912 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001913 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301914 return olterrors.NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001915 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001916 //this variable acts like a switch. When it is set, multicast flows are classified by eth_dst.
1917 //otherwise, classification is based on ipv4_dst by default.
1918 //the variable can be configurable in the future; it can be read from a configuration path in the kv store.
1919 mcastFlowClassificationByEthDst := false
1920
1921 if mcastFlowClassificationByEthDst {
1922 //replace ipDst with ethDst
1923 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1924 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1925 // replace ipv4_dst classifier with eth_dst
1926 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1927 delete(classifierInfo, Ipv4Dst)
1928 classifierInfo[EthDst] = multicastMac
1929 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1930 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001931 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001932 delete(classifierInfo, EthType)
Esin Karamanccb714b2019-11-29 15:02:06 +00001933
David K. Bainbridge794735f2020-02-11 21:01:37 -08001934 onuID := NoneOnuID
1935 uniID := NoneUniID
1936 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001937
David K. Bainbridge794735f2020-02-11 21:01:37 -08001938 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1939 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301940 return olterrors.NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001941 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001942
David K. Bainbridge794735f2020-02-11 21:01:37 -08001943 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301944 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001945 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1946 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001947 }
npujarec5762e2020-01-01 14:08:48 +05301948 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001949 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301950 return olterrors.NewErrNotFound("multicast-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001951 "interface-id": networkInterfaceID,
1952 "onu-id": onuID,
1953 "uni-id": uniID,
1954 "gem-port-id": gemPortID,
1955 "cookie": flowStoreCookie},
1956 err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001957 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001958 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1959 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301960 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001961 }
1962 groupID := actionInfo[GroupID].(uint32)
1963 multicastFlow := openoltpb2.Flow{
1964 FlowId: flowID,
1965 FlowType: Multicast,
1966 NetworkIntfId: int32(networkInterfaceID),
1967 GroupId: groupID,
1968 Classifier: classifierProto,
1969 Priority: int32(flow.Priority),
1970 Cookie: flow.Cookie}
1971
David K. Bainbridge794735f2020-02-11 21:01:37 -08001972 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301973 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001974 }
1975 log.Debug("multicast flow added to device successfully")
1976 //get cached group
1977 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1978 if err == nil {
1979 //calling groupAdd to set group members after multicast flow creation
1980 if f.ModifyGroup(ctx, group) {
1981 //cached group can be removed now
1982 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001983 }
1984 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001985
1986 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1987 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1988 int32(onuID),
1989 int32(uniID),
1990 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301991 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001992 }
1993 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001994}
1995
1996//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301997func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001998 if _, ok := classifierInfo[InPort]; ok {
1999 return classifierInfo[InPort].(uint32), nil
2000 }
2001 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05302002 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002003 if e == nil && len(nniPorts) > 0 {
2004 return nniPorts[0], nil
2005 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302006 return 0, olterrors.NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00002007}
2008
2009// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05302010func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00002011 log.Infow("add-group", log.Fields{"group": group})
2012 if group == nil {
2013 log.Warn("skipping nil group")
2014 return
2015 }
2016
2017 groupToOlt := openoltpb2.Group{
2018 GroupId: group.Desc.GroupId,
2019 Command: openoltpb2.Group_SET_MEMBERS,
2020 Action: f.buildGroupAction(),
2021 }
2022
2023 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302024 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002025 if err != nil {
2026 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
2027 return
2028 }
2029 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302030 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002031 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
2032 } else {
2033 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2034 }
2035}
2036
2037//buildGroupAction creates and returns a group action
2038func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2039 var actionCmd openoltpb2.ActionCmd
2040 var action openoltpb2.Action
2041 action.Cmd = &actionCmd
2042 //pop outer vlan
2043 action.Cmd.RemoveOuterTag = true
2044 return &action
2045}
2046
2047// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05302048func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00002049 log.Infow("modify-group", log.Fields{"group": group})
2050 if group == nil || group.Desc == nil {
2051 log.Warn("cannot modify group; group is nil")
2052 return false
2053 }
2054
2055 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2056 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302057 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002058
2059 if err != nil {
2060 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2061 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2062 return false
2063 }
2064
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002065 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002066 if groupExists {
2067 // group already exists
2068 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002069 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002070 } else {
2071 current = f.buildGroup(group.Desc.GroupId, nil)
2072 }
2073
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002074 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2075 // get members to be added
2076 membersToBeAdded := f.findDiff(current, new)
2077 // get members to be removed
2078 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002079
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002080 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2081 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002082
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002083 groupToOlt := openoltpb2.Group{
2084 GroupId: group.Desc.GroupId,
2085 }
2086 var added, removed = true, true
2087 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2088 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2089 groupToOlt.Members = membersToBeAdded
2090 //execute addMembers
2091 added = f.callGroupAddRemove(&groupToOlt)
2092 }
2093 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2094 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2095 groupToOlt.Members = membersToBeRemoved
2096 //execute removeMembers
2097 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002098 }
2099
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002100 //save the modified group
2101 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302102 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002103 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2104 }
2105 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002106 } else {
2107 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2108 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002109 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002110 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002111}
2112
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002113//callGroupAddRemove performs add/remove buckets operation for the indicated group
2114func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2115 if err := f.performGroupOperation(group); err != nil {
2116 st, _ := status.FromError(err)
2117 //ignore already exists error code
2118 if st.Code() != codes.AlreadyExists {
2119 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002120 }
2121 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002122 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002123}
2124
2125//findDiff compares group members and finds members which only exists in groups2
2126func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2127 var members []*openoltpb2.GroupMember
2128 for _, bucket := range group2.Members {
2129 if !f.contains(group1.Members, bucket) {
2130 // bucket does not exist and must be added
2131 members = append(members, bucket)
2132 }
2133 }
2134 return members
2135}
2136
2137//contains returns true if the members list contains the given member; false otherwise
2138func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2139 for _, groupMember := range members {
2140 if groupMember.InterfaceId == member.InterfaceId {
2141 return true
2142 }
2143 }
2144 return false
2145}
2146
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002147//performGroupOperation call performGroupOperation operation of openolt proto
2148func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002149 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2150 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2151 if err != nil {
2152 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2153 }
2154 return err
2155}
2156
2157//buildGroup build openoltpb2.Group from given group id and bucket list
2158func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2159 group := openoltpb2.Group{
2160 GroupId: groupID}
2161 // create members of the group
2162 if buckets != nil {
2163 for _, ofBucket := range buckets {
2164 member := f.buildMember(ofBucket)
2165 if member != nil && !f.contains(group.Members, member) {
2166 group.Members = append(group.Members, member)
2167 }
2168 }
2169 }
2170 return &group
2171}
2172
2173//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2174func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2175 var outPort uint32
2176 outPortFound := false
2177 for _, ofAction := range ofBucket.Actions {
2178 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2179 outPort = ofAction.GetOutput().Port
2180 outPortFound = true
2181 }
2182 }
2183
2184 if !outPortFound {
2185 log.Debugw("bucket skipped since no out port found in it",
2186 log.Fields{"ofBucket": ofBucket})
2187 return nil
2188 }
2189 interfaceID := IntfIDFromUniPortNum(outPort)
2190 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2191 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2192 member := openoltpb2.GroupMember{
2193 InterfaceId: interfaceID,
2194 InterfaceType: openoltpb2.GroupMember_PON,
2195 GemPortId: groupInfo.gemPortID,
2196 Priority: groupInfo.servicePriority,
2197 }
2198 //add member to the group
2199 return &member
2200 }
2201 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2202 log.Fields{"ofBucket": ofBucket})
2203 return nil
2204}
2205
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002206//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002207func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002208
2209 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302210 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002211 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302212 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302213 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302214 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002215
Manikkaraj kb1d51442019-07-23 10:41:02 -04002216 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002217 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002218 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2219 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2220 tpDownloadMsg,
2221 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2222 f.deviceHandler.deviceType,
2223 onuDevice.Type,
2224 onuDevice.Id,
2225 onuDevice.ProxyAddress.DeviceId, "")
2226 if sendErr != nil {
2227 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2228 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2229 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2230 return sendErr
2231 }
2232 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302233 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302234}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002235
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302236//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302237func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302238
2239 f.lockCache.Lock()
2240 defer f.lockCache.Unlock()
2241 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2242 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002243 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2244 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302245 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2246 return
2247 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002248 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2249}
2250
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302251//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302252func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302253 f.lockCache.Lock()
2254 defer f.lockCache.Unlock()
2255 onugem := f.onuGemInfo[intfID]
2256 // update the gem to the local cache as well as to kv strore
2257 for idx, onu := range onugem {
2258 if onu.OnuID == onuID {
2259 // check if gem already exists , else update the cache and kvstore
2260 for _, gem := range onu.GemPorts {
2261 if gem == gemPort {
2262 log.Debugw("Gem already in cache, no need to update cache and kv store",
2263 log.Fields{"gem": gemPort})
2264 return
2265 }
2266 }
2267 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2268 f.onuGemInfo[intfID] = onugem
2269 }
2270 }
npujarec5762e2020-01-01 14:08:48 +05302271 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302272 if err != nil {
2273 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002274 return
2275 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002276}
2277
2278// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002279
2280//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2281func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302282
2283 f.lockCache.Lock()
2284 defer f.lockCache.Unlock()
2285
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002286 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 +05302287 // get onuid from the onugem info cache
2288 onugem := f.onuGemInfo[intfID]
2289 for _, onu := range onugem {
2290 for _, gem := range onu.GemPorts {
2291 if gem == gemPortID {
2292 return onu.OnuID, nil
2293 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002294 }
2295 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302296 return uint32(0), olterrors.NewErrNotFound("onu-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002297 "serial-number": serialNumber,
2298 "interface-id": intfID,
2299 "gem-port-id": gemPortID},
2300 nil).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002301}
2302
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002303//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302304func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002305 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002306 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002307 var err error
2308
2309 if packetIn.IntfType == "pon" {
2310 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002311 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002312 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2313 return logicalPortNum, err
2314 }
2315 if packetIn.PortNo != 0 {
2316 logicalPortNum = packetIn.PortNo
2317 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002318 uniID := uint32(0) // FIXME - multi-uni support
2319 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002320 }
2321 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302322 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002323 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002324 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002325 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002326 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2327 "logicalPortNum": logicalPortNum,
2328 "IntfType": packetIn.IntfType,
2329 "packet": hex.EncodeToString(packetIn.Pkt),
2330 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002331 return logicalPortNum, nil
2332}
2333
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002334//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302335func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002336 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002337 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302338
2339 f.lockCache.Lock()
2340 defer f.lockCache.Unlock()
2341 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2342
2343 gemPortID, ok := f.packetInGemPort[pktInkey]
2344 if ok {
2345 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2346 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002347 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302348 //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 +05302349 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302350 if err == nil {
2351 if gemPortID != 0 {
2352 f.packetInGemPort[pktInkey] = gemPortID
2353 log.Debugw("Found gem port from kv store and updating cache with gemport",
2354 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2355 return gemPortID, nil
2356 }
2357 }
2358 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2359 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002360}
2361
npujarec5762e2020-01-01 14:08:48 +05302362func installFlowOnAllGemports(ctx context.Context,
2363 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002364 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002365 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302366 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302367 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302368 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302369 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002370 args map[string]uint32,
2371 classifier map[string]interface{}, action map[string]interface{},
2372 logicalFlow *ofp.OfpFlowStats,
2373 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302374 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002375 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002376 vlanID ...uint32) {
2377 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302378
2379 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2380 var gemPortID uint32
2381 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2382 // We need to trim prefix "0b", before further processing
2383 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2384 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2385 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2386 // If a particular character in the string is set to '1', identify the index of this character from
2387 // the LSB position which marks the PCP bit consumed by the given gem port.
2388 // This PCP bit now becomes a classifier in the flow.
2389 if pbitSet == BinaryBit1 {
2390 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2391 gemPortID = gemPortAttribute.GemportID
2392 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2393 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2394 } else if FlowType == EapolFlow {
2395 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2396 } else {
2397 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2398 return
2399 }
2400 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002401 }
2402 }
2403}
2404
David K. Bainbridge794735f2020-02-11 21:01:37 -08002405func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002406 log.Debug("Adding trap-dhcp-of-nni-flow")
2407 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002408 classifier[PacketTagType] = DoubleTag
2409 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002410 /* We manage flowId resource pool on per PON port basis.
2411 Since this situation is tricky, as a hack, we pass the NNI port
2412 index (network_intf_id) as PON port Index for the flowId resource
2413 pool. Also, there is no ONU Id available for trapping DHCP packets
2414 on NNI port, use onu_id as -1 (invalid)
2415 ****************** CAVEAT *******************
2416 This logic works if the NNI Port Id falls within the same valid
2417 range of PON Port Ids. If this doesn't work for some OLT Vendor
2418 we need to have a re-look at this.
2419 *********************************************
2420 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002421 onuID := -1
2422 uniID := -1
2423 gemPortID := -1
2424 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002425 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302426 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302427 return olterrors.NewErrNotFound("nni-intreface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002428 "classifier": classifier,
2429 "action": action},
2430 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302431 }
2432
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002433 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302434 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002435 log.Debug("Flow-exists-not-re-adding")
2436 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002437 }
npujarec5762e2020-01-01 14:08:48 +05302438 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002439 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302440 return olterrors.NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002441 "interface-id": networkInterfaceID,
2442 "onu-id": onuID,
2443 "uni-id": uniID,
2444 "gem-port-id": gemPortID,
2445 "cookie": flowStoreCookie},
2446 err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002447 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002448 classifierProto, err := makeOpenOltClassifierField(classifier)
2449 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302450 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002451 }
2452 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002453 actionProto, err := makeOpenOltActionField(action)
2454 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302455 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002456 }
2457 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002458 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2459 OnuId: int32(onuID), // OnuId not required
2460 UniId: int32(uniID), // UniId not used
2461 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002462 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002463 AllocId: int32(allocID), // AllocId not used
2464 NetworkIntfId: int32(networkInterfaceID),
2465 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002466 Classifier: classifierProto,
2467 Action: actionProto,
2468 Priority: int32(logicalFlow.Priority),
2469 Cookie: logicalFlow.Cookie,
2470 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002471 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302472 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002473 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002474 log.Debug("DHCP trap on NNI flow added to device successfully")
2475 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2476 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2477 int32(onuID),
2478 int32(uniID),
2479 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302480 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08002481 }
2482 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002483}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002484
Esin Karamanae41e2b2019-12-17 18:13:13 +00002485//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2486func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2487 var packetType string
2488 ovid, ivid := false, false
2489 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2490 vid := vlanID & VlanvIDMask
2491 if vid != ReservedVlan {
2492 ovid = true
2493 }
2494 }
2495 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2496 vid := uint32(metadata)
2497 if vid != ReservedVlan {
2498 ivid = true
2499 }
2500 }
2501 if ovid && ivid {
2502 packetType = DoubleTag
2503 } else if !ovid && !ivid {
2504 packetType = Untagged
2505 } else {
2506 packetType = SingleTag
2507 }
2508 return packetType
2509}
2510
2511//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002512func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002513 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2514 action := make(map[string]interface{})
2515 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2516 action[TrapToHost] = true
2517 /* We manage flowId resource pool on per PON port basis.
2518 Since this situation is tricky, as a hack, we pass the NNI port
2519 index (network_intf_id) as PON port Index for the flowId resource
2520 pool. Also, there is no ONU Id available for trapping packets
2521 on NNI port, use onu_id as -1 (invalid)
2522 ****************** CAVEAT *******************
2523 This logic works if the NNI Port Id falls within the same valid
2524 range of PON Port Ids. If this doesn't work for some OLT Vendor
2525 we need to have a re-look at this.
2526 *********************************************
2527 */
2528 onuID := -1
2529 uniID := -1
2530 gemPortID := -1
2531 allocID := -1
2532 networkInterfaceID, err := getNniIntfID(classifier, action)
2533 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302534 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002535 "classifier": classifier,
2536 "action": action},
2537 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002538 }
2539 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302540 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002541 log.Debug("igmp-flow-exists-not-re-adding")
2542 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002543 }
npujarec5762e2020-01-01 14:08:48 +05302544 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002545 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302546 return olterrors.NewErrNotFound("igmp-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002547 "interface-id": networkInterfaceID,
2548 "onu-id": onuID,
2549 "uni-id": uniID,
2550 "gem-port-id": gemPortID,
2551 "cookie": flowStoreCookie},
2552 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002553 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002554 classifierProto, err := makeOpenOltClassifierField(classifier)
2555 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302556 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002557 }
2558 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002559 actionProto, err := makeOpenOltActionField(action)
2560 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302561 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002562 }
2563 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2564 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2565 OnuId: int32(onuID), // OnuId not required
2566 UniId: int32(uniID), // UniId not used
2567 FlowId: flowID,
2568 FlowType: Downstream,
2569 AllocId: int32(allocID), // AllocId not used
2570 NetworkIntfId: int32(networkInterfaceID),
2571 GemportId: int32(gemPortID), // GemportId not used
2572 Classifier: classifierProto,
2573 Action: actionProto,
2574 Priority: int32(logicalFlow.Priority),
2575 Cookie: logicalFlow.Cookie,
2576 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002577 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302578 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +00002579 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002580 log.Debug("IGMP Trap on NNI flow added to device successfully")
2581 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2582 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2583 int32(onuID),
2584 int32(uniID),
2585 flowID, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302586 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08002587 }
2588 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002589}
2590
salmansiddiqui7ac62132019-08-22 03:58:50 +00002591func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2592 if MeterID == 0 { // This should never happen
Thomas Lee S94109f12020-03-03 16:39:29 +05302593 return "", olterrors.NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002594 }
2595 if Dir == tp_pb.Direction_UPSTREAM {
2596 return "upstream", nil
2597 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2598 return "downstream", nil
2599 }
2600 return "", nil
2601}
2602
npujarec5762e2020-01-01 14:08:48 +05302603func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002604 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2605 TpID uint32, uni string) {
2606 var gemPort uint32
2607 intfID := args[IntfID]
2608 onuID := args[OnuID]
2609 uniID := args[UniID]
2610 portNo := args[PortNo]
2611 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002612 if ipProto, ok := classifierInfo[IPProto]; ok {
2613 if ipProto.(uint32) == IPProtoDhcp {
2614 log.Info("Adding DHCP flow")
2615 if pcp, ok := classifierInfo[VlanPcp]; ok {
2616 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2617 tp_pb.Direction_UPSTREAM,
2618 pcp.(uint32))
2619 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302620 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002621 } else {
2622 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302623 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002624 }
2625
2626 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002627 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2628 if pcp, ok := classifierInfo[VlanPcp]; ok {
2629 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2630 tp_pb.Direction_UPSTREAM,
2631 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302632 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002633 } else {
2634 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302635 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002636 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002637 } else {
2638 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2639 return
2640 }
2641 } else if ethType, ok := classifierInfo[EthType]; ok {
2642 if ethType.(uint32) == EapEthType {
2643 log.Info("Adding EAPOL flow")
2644 var vlanID uint32
2645 if val, ok := classifierInfo[VlanVid]; ok {
2646 vlanID = (val.(uint32)) & VlanvIDMask
2647 } else {
2648 vlanID = DefaultMgmtVlan
2649 }
2650 if pcp, ok := classifierInfo[VlanPcp]; ok {
2651 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2652 tp_pb.Direction_UPSTREAM,
2653 pcp.(uint32))
2654
Girish Gowdrafae935c2020-02-17 19:21:44 +05302655 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002656 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302657 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002658 }
2659 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002660 } else if _, ok := actionInfo[PushVlan]; ok {
2661 log.Info("Adding upstream data rule")
2662 if pcp, ok := classifierInfo[VlanPcp]; ok {
2663 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2664 tp_pb.Direction_UPSTREAM,
2665 pcp.(uint32))
2666 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302667 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002668 } else {
2669 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302670 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002671 }
2672 } else if _, ok := actionInfo[PopVlan]; ok {
2673 log.Info("Adding Downstream data rule")
2674 if pcp, ok := classifierInfo[VlanPcp]; ok {
2675 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002676 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002677 pcp.(uint32))
2678 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302679 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002680 } else {
2681 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302682 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002683 }
2684 } else {
2685 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2686 return
2687 }
2688 // Send Techprofile download event to child device in go routine as it takes time
2689 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2690}
2691
Gamze Abakafee36392019-10-03 11:17:24 +00002692func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2693 flowIDList := f.flowsUsedByGemPort[gemPK]
2694 if len(flowIDList) > 1 {
2695 return true
2696 }
2697 return false
2698}
2699
npujarec5762e2020-01-01 14:08:48 +05302700func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2701 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002702 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2703 for _, currentGemPort := range currentGemPorts {
2704 for _, tpGemPort := range tpGemPorts {
2705 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2706 return true, currentGemPort
2707 }
2708 }
2709 }
Girish Gowdra54934262019-11-13 14:19:55 +05302710 if tpInst.InstanceCtrl.Onu == "single-instance" {
2711 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302712 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2713 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302714
2715 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2716 // still be used on other uni ports.
2717 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2718 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302719 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302720 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302721 for i := 0; i < len(tpInstances); i++ {
2722 tpI := tpInstances[i]
2723 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302724 for _, tpGemPort := range tpGemPorts {
2725 if tpGemPort.GemportID != gemPortID {
2726 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2727 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302728 }
2729 }
2730 }
2731 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302732 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002733 return false, 0
2734}
2735
salmansiddiqui7ac62132019-08-22 03:58:50 +00002736func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002737 for _, field := range flows.GetOfbFields(flow) {
2738 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002739 classifierInfo[EthType] = field.GetEthType()
2740 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002741 } else if field.Type == flows.ETH_DST {
2742 classifierInfo[EthDst] = field.GetEthDst()
2743 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002744 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002745 classifierInfo[IPProto] = field.GetIpProto()
2746 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002747 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002748 classifierInfo[InPort] = field.GetPort()
2749 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002750 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302751 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002752 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002753 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002754 classifierInfo[VlanPcp] = field.GetVlanPcp()
2755 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002756 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002757 classifierInfo[UDPDst] = field.GetUdpDst()
2758 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002759 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002760 classifierInfo[UDPSrc] = field.GetUdpSrc()
2761 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002762 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002763 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2764 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002765 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002766 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2767 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002768 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002769 classifierInfo[Metadata] = field.GetTableMetadata()
2770 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002771 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002772 classifierInfo[TunnelID] = field.GetTunnelId()
2773 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2774 } else {
2775 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2776 return
2777 }
2778 }
2779}
2780
2781func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002782 for _, action := range flows.GetActions(flow) {
2783 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002784 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002785 actionInfo[Output] = out.GetPort()
2786 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002787 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302788 return olterrors.NewErrInvalidValue(log.Fields{"output-port": nil}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002789 }
Scott Baker355d1742019-10-24 10:57:52 -07002790 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002791 actionInfo[PopVlan] = true
2792 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002793 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002794 if out := action.GetPush(); out != nil {
2795 if tpid := out.GetEthertype(); tpid != 0x8100 {
2796 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2797 } else {
2798 actionInfo[PushVlan] = true
2799 actionInfo[TPID] = tpid
2800 log.Debugw("action-type-push-vlan",
2801 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2802 }
2803 }
Scott Baker355d1742019-10-24 10:57:52 -07002804 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002805 if out := action.GetSetField(); out != nil {
2806 if field := out.GetField(); field != nil {
2807 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
Thomas Lee S94109f12020-03-03 16:39:29 +05302808 return olterrors.NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002809 }
2810 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002811 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002812 }
2813 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002814 } else if action.Type == flows.GROUP {
2815 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002816 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302817 return olterrors.NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002818 }
2819 }
2820 return nil
2821}
2822
Esin Karamanccb714b2019-11-29 15:02:06 +00002823func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2824 if ofbField := field.GetOfbField(); ofbField != nil {
2825 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2826 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2827 actionInfo[VlanVid] = vlan & 0xfff
2828 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2829 } else {
2830 log.Error("No Invalid vlan id in set vlan-vid action")
2831 }
2832 } else {
2833 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2834 }
2835 }
2836}
2837
2838func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2839 if action.GetGroup() == nil {
2840 log.Warn("No group entry found in the group action")
2841 } else {
2842 actionInfo[GroupID] = action.GetGroup().GroupId
2843 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2844 }
2845}
2846
salmansiddiqui7ac62132019-08-22 03:58:50 +00002847func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002848 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002849 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2850 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2851 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002852 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002853 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002854 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 +00002855 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302856 return olterrors.NewErrNotFound("child-in-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002857 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
2858 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002859 }
2860 }
2861 } else {
2862 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2863 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002864 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002865 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002866 actionInfo[Output] = uniPort
2867 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 +00002868 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302869 return olterrors.NewErrNotFound("out-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002870 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
2871 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002872 }
2873 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2874 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002875 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002876 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002877 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2878 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002879 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302880 return olterrors.NewErrNotFound("nni-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002881 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2882 "in-port": classifierInfo[InPort].(uint32),
2883 "out-port": actionInfo[Output].(uint32),
2884 "flow": flow}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002885 }
2886 }
2887 }
2888 return nil
2889}
Gamze Abakafee36392019-10-03 11:17:24 +00002890
Chaitrashree G S90a17952019-11-14 21:51:21 -05002891func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002892 /* Metadata 8 bytes:
2893 Most Significant 2 Bytes = Inner VLAN
2894 Next 2 Bytes = Tech Profile ID(TPID)
2895 Least Significant 4 Bytes = Port ID
2896 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2897 subscriber related flows.
2898 */
2899 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2900 if metadata == 0 {
Thomas Lee S94109f12020-03-03 16:39:29 +05302901 return 0, olterrors.NewErrNotFound("metadata", log.Fields{"flow": flow}, nil).Log()
Gamze Abakafee36392019-10-03 11:17:24 +00002902 }
2903 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002904 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002905}
2906
2907func appendUnique(slice []uint32, item uint32) []uint32 {
2908 for _, sliceElement := range slice {
2909 if sliceElement == item {
2910 return slice
2911 }
2912 }
2913 return append(slice, item)
2914}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302915
2916// getNniIntfID gets nni intf id from the flow classifier/action
2917func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2918
2919 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2920 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002921 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2922 if err != nil {
2923 log.Debugw("invalid-action-port-number",
2924 log.Fields{
2925 "port-number": action[Output].(uint32),
2926 "error": err})
2927 return uint32(0), err
2928 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302929 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2930 return intfID, nil
2931 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002932 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2933 if err != nil {
2934 log.Debugw("invalid-classifier-port-number",
2935 log.Fields{
2936 "port-number": action[Output].(uint32),
2937 "error": err})
2938 return uint32(0), err
2939 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302940 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2941 return intfID, nil
2942 }
2943 return uint32(0), nil
2944}
2945
2946// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302947func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302948 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2949
2950 f.lockCache.Lock()
2951 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002952 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302953 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002954 if lookupGemPort == gemPort {
2955 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2956 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2957 return
2958 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302959 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002960 f.packetInGemPort[pktInkey] = gemPort
2961
npujarec5762e2020-01-01 14:08:48 +05302962 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002963 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 +05302964 return
2965}
2966
2967// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302968func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302969
2970 f.lockCache.Lock()
2971 defer f.lockCache.Unlock()
2972 onugem := f.onuGemInfo[intfID]
2973 for idx, onu := range onugem {
2974 if onu.OnuID == onuID {
2975 for _, uni := range onu.UniPorts {
2976 if uni == portNum {
2977 log.Debugw("uni already in cache, no need to update cache and kv store",
2978 log.Fields{"uni": portNum})
2979 return
2980 }
2981 }
2982 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2983 f.onuGemInfo[intfID] = onugem
2984 }
2985 }
npujarec5762e2020-01-01 14:08:48 +05302986 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302987}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302988
npujarec5762e2020-01-01 14:08:48 +05302989func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2990 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302991 if err != nil {
2992 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2993 return
2994 }
2995 for gem, FlowIDs := range flowIDsList {
2996 gemPK := gemPortKey{intf, uint32(gem)}
2997 f.flowsUsedByGemPort[gemPK] = FlowIDs
2998 }
2999 return
3000}
Esin Karamanccb714b2019-11-29 15:02:06 +00003001
3002//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
3003//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05303004func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
3005 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00003006 if err != nil {
3007 log.Error("Failed to get pon interface to multicast queue map")
3008 return
3009 }
3010 for intf, queueInfo := range storedMulticastQueueMap {
3011 q := queueInfoBrief{
3012 gemPortID: queueInfo[0],
3013 servicePriority: queueInfo[1],
3014 }
3015 f.interfaceToMcastQueueMap[intf] = &q
3016 }
3017}
3018
3019//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
3020//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
3021//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05303022func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
3023 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00003024 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05303025 return nil, false, olterrors.NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00003026 }
3027 if exists {
3028 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3029 }
3030 return nil, exists, nil
3031}
3032
3033func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3034 groupDesc := ofp.OfpGroupDesc{
3035 Type: ofp.OfpGroupType_OFPGT_ALL,
3036 GroupId: groupID,
3037 }
3038 groupEntry := ofp.OfpGroupEntry{
3039 Desc: &groupDesc,
3040 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003041 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003042 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003043 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003044 bucket := ofp.OfpBucket{
3045 Actions: acts,
3046 }
3047 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003048 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003049 return &groupEntry
3050}