blob: b229f829cf62a3950b07001d04fee7b9057f9030 [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 {
Girish Kumarf26e4882020-03-05 06:49:10 +0000238 log.Errorw("Error while populating tech profile mgr", log.Fields{"error": err})
manikkaraj kbf256be2019-03-25 00:13:48 +0530239 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 {
Girish Kumarf26e4882020-03-05 06:49:10 +0000360 return olterrors.NewErrNotFound("meter", log.Fields{"intfId": sq.intfID, "onuId": sq.onuID, "uniId": sq.uniID}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400361 }
Girish Kumarf26e4882020-03-05 06:49:10 +0000362
Manikkaraj kb1d51442019-07-23 10:41:02 -0400363 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,
Girish Kumarf26e4882020-03-05 06:49:10 +0000371 "meter-id-in-flow": sq.meterID}, nil)
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 {
Girish Kumarf26e4882020-03-05 06:49:10 +0000383 return olterrors.NewErrNotFound("scheduler-config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "tpInst": sq.tpInst}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000384 }
385
Manikkaraj kb1d51442019-07-23 10:41:02 -0400386 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000387 if sq.flowMetadata != nil {
388 for _, meter := range sq.flowMetadata.Meters {
389 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400390 meterConfig = meter
391 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
392 break
393 }
394 }
395 } else {
396 log.Error("Flow-metadata-is-not-present-in-flow")
397 }
398 if meterConfig == nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530399 return olterrors.NewErrNotFound("meterbands", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800400 "reason": "Could-not-get-meterbands-from-flowMetadata",
401 "flow-metadata": sq.flowMetadata,
Girish Kumarf26e4882020-03-05 06:49:10 +0000402 "meter-id": sq.meterID}, nil)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400403 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000404 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
Thomas Lee S94109f12020-03-03 16:39:29 +0530405 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800406 "reason": "Invalid-number-of-bands-in-meter",
407 "meterband-count": len(meterConfig.Bands),
408 "metabands": meterConfig.Bands,
Girish Kumarf26e4882020-03-05 06:49:10 +0000409 "meter-id": sq.meterID}, nil)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400410 }
411 cir := meterConfig.Bands[0].Rate
412 cbs := meterConfig.Bands[0].BurstSize
413 eir := meterConfig.Bands[1].Rate
414 ebs := meterConfig.Bands[1].BurstSize
415 pir := cir + eir
416 pbs := cbs + ebs
417 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
418
Gamze Abakafee36392019-10-03 11:17:24 +0000419 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400420
npujarec5762e2020-01-01 14:08:48 +0530421 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000422 return olterrors.NewErrAdapter("failure-pushing-traffic-scheduler-and-queues-to-device", log.Fields{"intfID": sq.intfID, "direction": sq.direction}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400423 }
424
salmansiddiqui7ac62132019-08-22 03:58:50 +0000425 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400426 * store the meter id on the KV store, for further reference.
427 */
npujarec5762e2020-01-01 14:08:48 +0530428 if err := f.resourceMgr.UpdateMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID, meterConfig); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000429 return olterrors.NewErrAdapter("failed-updating-meter-id", log.Fields{"onu-id": sq.onuID, "meter-id": sq.meterID}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400430 }
431 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
432 "Meter": meterConfig})
433 return nil
434}
435
npujarec5762e2020-01-01 14:08:48 +0530436func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000437
438 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
439
440 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000441 return olterrors.NewErrAdapter("unable-to-construct-traffic-queue-configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000442 }
443
444 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530445 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000446 IntfId: sq.intfID, OnuId: sq.onuID,
447 UniId: sq.uniID, PortNo: sq.uniPort,
448 TrafficScheds: TrafficSched}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000449 return olterrors.NewErrAdapter("failed-to-create-traffic-schedulers-in-device", log.Fields{"TrafficScheds": TrafficSched}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000450 }
451
452 // On receiving the CreateTrafficQueues request, the driver should create corresponding
453 // downstream queues.
454 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530455 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000456 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
457 UniId: sq.uniID, PortNo: sq.uniPort,
458 TrafficQueues: trafficQueues}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000459 return olterrors.NewErrAdapter("failed-to-create-traffic-queues-in-device", log.Fields{"TrafficQueues": trafficQueues}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000460 }
461
Esin Karamanccb714b2019-11-29 15:02:06 +0000462 if sq.direction == tp_pb.Direction_DOWNSTREAM {
463 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
464 if len(multicastTrafficQueues) > 0 {
465 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
466 //assumed that there is only one queue per PON for the multicast service
467 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
468 //just put it in interfaceToMcastQueueMap to use for building group members
469 multicastQueuePerPonPort := multicastTrafficQueues[0]
470 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
471 gemPortID: multicastQueuePerPonPort.GemportId,
472 servicePriority: multicastQueuePerPonPort.Priority,
473 }
474 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530475 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000476 multicastQueuePerPonPort.GemportId,
477 multicastQueuePerPonPort.Priority)
478 }
479 }
480 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000481 return nil
482}
483
salmansiddiqui7ac62132019-08-22 03:58:50 +0000484// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530485func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400486
487 var Direction string
488 var SchedCfg *tp_pb.SchedulerConfig
489 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000490 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
491 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
492 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000493 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400494 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000495 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000496 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400497 Direction = "downstream"
498 }
499
Girish Kumar8f73fe02019-12-09 13:19:37 +0000500 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000501 return olterrors.NewErrNotFound("scheduler-config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000502 }
503
npujarec5762e2020-01-01 14:08:48 +0530504 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400505 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000506 return olterrors.NewErrNotFound("meter", log.Fields{"onuID": sq.onuID}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400507 }
508 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000509 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 -0400510 return nil
511 }
512 cir := KVStoreMeter.Bands[0].Rate
513 cbs := KVStoreMeter.Bands[0].BurstSize
514 eir := KVStoreMeter.Bands[1].Rate
515 ebs := KVStoreMeter.Bands[1].BurstSize
516 pir := cir + eir
517 pbs := cbs + ebs
518
519 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
520
Gamze Abakafee36392019-10-03 11:17:24 +0000521 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000522
523 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
524 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000525 return olterrors.NewErrAdapter("unable-to-construct-traffic-queue-configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction}, err)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000526 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400527
npujarec5762e2020-01-01 14:08:48 +0530528 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000529 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
530 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400531 TrafficQueues: TrafficQueues}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000532 return olterrors.NewErrAdapter("unable-to-remove-traffic-queues-from-device",
533 log.Fields{"intfID": sq.intfID, "TrafficQueues": TrafficQueues}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400534 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000535 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530536 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000537 IntfId: sq.intfID, OnuId: sq.onuID,
538 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400539 TrafficScheds: TrafficSched}); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000540 return olterrors.NewErrAdapter("unable-to-remove-traffic-schedulers-from-device",
541 log.Fields{"intfID": sq.intfID, "TrafficSchedulers": TrafficSched}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400542 }
543
salmansiddiqui7ac62132019-08-22 03:58:50 +0000544 log.Debug("Removed traffic schedulers successfully")
545
546 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400547 * delete the meter id on the KV store.
548 */
npujarec5762e2020-01-01 14:08:48 +0530549 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400550 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +0000551 return olterrors.NewErrAdapter("unable-to-remove-meter", log.Fields{"onu": sq.onuID, "meter": KVStoreMeter.MeterId}, err)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400552 }
553 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
554 return err
555}
556
Gamze Abakafee36392019-10-03 11:17:24 +0000557// This function allocates tconts and GEM ports for an ONU
npujarec5762e2020-01-01 14:08:48 +0530558func (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 +0000559 var allocIDs []uint32
560 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530561 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530562 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000563 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000564
npujarec5762e2020-01-01 14:08:48 +0530565 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(ctx, intfID, onuID, uniID)
566 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400567
568 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530569
570 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
571
Manikkaraj kb1d51442019-07-23 10:41:02 -0400572 // Check tech profile instance already exists for derived port name
npujarec5762e2020-01-01 14:08:48 +0530573 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(ctx, TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000574 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530575 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
npujarec5762e2020-01-01 14:08:48 +0530576 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(ctx, TpID, uni, intfID)
Girish Kumar8f73fe02019-12-09 13:19:37 +0000577 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530578 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000579 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000580 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530581 }
npujarec5762e2020-01-01 14:08:48 +0530582 f.resourceMgr.UpdateTechProfileIDForOnu(ctx, intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530583 } else {
584 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530585 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530586 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400587 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000588 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
589 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530590 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400591 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000592 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400593 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530594 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400595 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000596 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
597 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
npujarec5762e2020-01-01 14:08:48 +0530598 if err := f.CreateSchedulerQueues(ctx, sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400599 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000600 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400601 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530602 }
Gamze Abakafee36392019-10-03 11:17:24 +0000603
604 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000605 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000606 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400607 }
Gamze Abakafee36392019-10-03 11:17:24 +0000608
Girish Gowdra3d633032019-12-10 16:37:05 +0530609 if tpInstanceExists {
610 return allocID, gemPortIDs, techProfileInstance
611 }
612
613 allocIDs = appendUnique(allocIDs, allocID)
614 for _, gemPortID := range gemPortIDs {
615 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
616 }
617
Gamze Abakafee36392019-10-03 11:17:24 +0000618 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530619 // Send Tconts and GEM ports to KV store
npujarec5762e2020-01-01 14:08:48 +0530620 f.storeTcontsGEMPortsIntoKVStore(ctx, intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000621 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530622}
623
npujarec5762e2020-01-01 14:08:48 +0530624func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530625
626 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700627 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530628 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
npujarec5762e2020-01-01 14:08:48 +0530629 if err := f.resourceMgr.UpdateAllocIdsForOnu(ctx, intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530630 log.Error("Errow while uploading allocID to KV store")
631 }
npujarec5762e2020-01-01 14:08:48 +0530632 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(ctx, intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530633 log.Error("Errow while uploading GEMports to KV store")
634 }
npujarec5762e2020-01-01 14:08:48 +0530635 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(ctx, gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530636 log.Error("Errow while uploading gemtopon map to KV store")
637 }
638 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400639 for _, gemPort := range gemPortIDs {
npujarec5762e2020-01-01 14:08:48 +0530640 f.addGemPortToOnuInfoMap(ctx, intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400641 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530642}
643
644func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000645 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530646 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000647 for _, intfID := range techRange.IntfIds {
648 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400649 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000650 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530651 }
652 }
653 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400654 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
Thomas Lee S94109f12020-03-03 16:39:29 +0530655 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800656 "reason": "TP count does not match number of PON ports",
657 "tech-profile-count": tpCount,
Girish Kumarf26e4882020-03-05 06:49:10 +0000658 "pon-port-count": f.resourceMgr.DevInfo.GetPonPorts()}, nil)
manikkaraj kbf256be2019-03-25 00:13:48 +0530659 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400660 log.Infow("Populated techprofile for ponports successfully",
661 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530662 return nil
663}
664
npujarec5762e2020-01-01 14:08:48 +0530665func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530666 portNo uint32, uplinkClassifier map[string]interface{},
667 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800668 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700669 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530670 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800671 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700672 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530673 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530674}
675
npujarec5762e2020-01-01 14:08:48 +0530676func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530677 portNo uint32, downlinkClassifier map[string]interface{},
678 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800679 allocID uint32, gemportID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700680 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530681 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
682 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400683 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
684 if vlan, exists := downlinkClassifier[VlanVid]; exists {
685 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700686 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400687 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
688 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800689 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400690 }
691 }
692 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530693 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400694
Manikkaraj k884c1242019-04-11 16:26:42 +0530695 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700696 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400697 // vlan_vid is a uint32. must be type asserted as such or conversion fails
698 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530699 if ok {
700 downlinkAction[VlanVid] = dlClVid & 0xfff
701 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +0530702 return olterrors.NewErrInvalidValue(log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800703 "reason": "failed to convert VLANID classifier",
704 "vlan-id": VlanVid}, nil).Log()
Girish Gowdra26f344b2019-10-23 14:39:13 +0530705 }
706
David K. Bainbridge794735f2020-02-11 21:01:37 -0800707 return f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700708 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530709}
710
npujarec5762e2020-01-01 14:08:48 +0530711func (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 +0530712 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
David K. Bainbridge794735f2020-02-11 21:01:37 -0800713 allocID uint32, gemPortID uint32) error {
Manikkaraj k884c1242019-04-11 16:26:42 +0530714 /* One of the OLT platform (Broadcom BAL) requires that symmetric
715 flows require the same flow_id to be used across UL and DL.
716 Since HSIA flow is the only symmetric flow currently, we need to
717 re-use the flow_id across both direction. The 'flow_category'
718 takes priority over flow_cookie to find any available HSIA_FLOW
719 id for the ONU.
720 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700721 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
722 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530723 "logicalFlow": *logicalFlow})
Girish Gowdrafae935c2020-02-17 19:21:44 +0530724 var vlanPbit uint32 = 0xff // means no pbit
Manikkaraj kb1d51442019-07-23 10:41:02 -0400725 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000726 vlanPbit = classifier[VlanPcp].(uint32)
727 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800728 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +0530729 log.Debugw("pbit-not-found-in-flow", log.Fields{"vlan-pcp": VlanPcp})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400730 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700731 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530732 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800733 log.Debug("flow-already-exists")
734 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530735 }
npujarec5762e2020-01-01 14:08:48 +0530736 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530737 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530738 return olterrors.NewErrNotFound("hsia-flow-id", log.Fields{"direction": direction}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530739 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800740 classifierProto, err := makeOpenOltClassifierField(classifier)
741 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530742 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530743 }
744 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800745 actionProto, err := makeOpenOltActionField(action)
746 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530747 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530748 }
749 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800750 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530751 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530752 return olterrors.NewErrNotFound("nni-interface-id",
David K. Bainbridge794735f2020-02-11 21:01:37 -0800753 log.Fields{
754 "classifier": classifier,
755 "action": action,
756 }, err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530757 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700758 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
759 OnuId: int32(onuID),
760 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000761 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530762 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700763 AllocId: int32(allocID),
764 NetworkIntfId: int32(networkIntfID),
765 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530766 Classifier: classifierProto,
767 Action: actionProto,
768 Priority: int32(logicalFlow.Priority),
769 Cookie: logicalFlow.Cookie,
770 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -0800771 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530772 return olterrors.NewErrFlowOp("add", flowID, nil, err).Log()
Manikkaraj k884c1242019-04-11 16:26:42 +0530773 }
David K. Bainbridge794735f2020-02-11 21:01:37 -0800774 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
775 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
776 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
777 flow.OnuId,
778 flow.UniId,
779 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530780 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800781 }
782 return nil
Manikkaraj k884c1242019-04-11 16:26:42 +0530783}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000784
David K. Bainbridge794735f2020-02-11 21:01:37 -0800785func (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 +0530786
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530787 networkIntfID, err := getNniIntfID(classifier, action)
788 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530789 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800790 "classifier": classifier,
791 "action": action},
792 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530793 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530794
795 // Clear the action map
796 for k := range action {
797 delete(action, k)
798 }
799
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700800 action[TrapToHost] = true
801 classifier[UDPSrc] = uint32(68)
802 classifier[UDPDst] = uint32(67)
803 classifier[PacketTagType] = SingleTag
804 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530805
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700806 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530807 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530808 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -0800809 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530810 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530811
David K. Bainbridge794735f2020-02-11 21:01:37 -0800812 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 +0530813
814 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530815 return olterrors.NewErrNotFound("flow", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800816 "interface-id": intfID,
817 "gem-port": gemPortID,
818 "cookie": flowStoreCookie},
819 err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530820 }
821
822 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
823
David K. Bainbridge794735f2020-02-11 21:01:37 -0800824 classifierProto, err := makeOpenOltClassifierField(classifier)
825 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530826 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530827 }
828 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800829 actionProto, err := makeOpenOltActionField(action)
830 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530831 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530832 }
833
David K. Bainbridge794735f2020-02-11 21:01:37 -0800834 dhcpFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700835 OnuId: int32(onuID),
836 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530837 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700838 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700839 AllocId: int32(allocID),
840 NetworkIntfId: int32(networkIntfID),
841 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530842 Classifier: classifierProto,
843 Action: actionProto,
844 Priority: int32(logicalFlow.Priority),
845 Cookie: logicalFlow.Cookie,
846 PortNo: portNo}
847
David K. Bainbridge794735f2020-02-11 21:01:37 -0800848 if err := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530849 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"dhcp-flow": dhcpFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800850 }
851 log.Debug("DHCP UL flow added to device successfully")
852 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
853 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
854 dhcpFlow.OnuId,
855 dhcpFlow.UniId,
856 dhcpFlow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530857 return olterrors.NewErrPersistence("update", "flow", dhcpFlow.FlowId, log.Fields{"flow": dhcpFlow}, err).Log()
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530858 }
859
David K. Bainbridge794735f2020-02-11 21:01:37 -0800860 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530861}
862
Esin Karamanae41e2b2019-12-17 18:13:13 +0000863//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530864func (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 -0800865 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) error {
866 return f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000867}
868
869//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530870func (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 -0800871 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000872
873 networkIntfID, err := getNniIntfID(classifier, action)
874 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530875 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800876 "classifier": classifier,
877 "action": action},
878 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000879 }
880
881 // Clear the action map
882 for k := range action {
883 delete(action, k)
884 }
885
886 action[TrapToHost] = true
887 classifier[PacketTagType] = SingleTag
888 delete(classifier, VlanVid)
889
890 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530891 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800892 log.Debug("Flow-exists-not-re-adding")
893 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000894 }
895
npujarec5762e2020-01-01 14:08:48 +0530896 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 +0000897
898 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530899 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800900 "interface-id": intfID,
901 "oni-id": onuID,
902 "cookie": flowStoreCookie,
903 "flow-type": flowType},
904 err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000905 }
906
907 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
908
David K. Bainbridge794735f2020-02-11 21:01:37 -0800909 classifierProto, err := makeOpenOltClassifierField(classifier)
910 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530911 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000912 }
913 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800914 actionProto, err := makeOpenOltActionField(action)
915 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530916 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000917 }
918
David K. Bainbridge794735f2020-02-11 21:01:37 -0800919 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Esin Karamanae41e2b2019-12-17 18:13:13 +0000920 OnuId: int32(onuID),
921 UniId: int32(uniID),
922 FlowId: flowID,
923 FlowType: Upstream,
924 AllocId: int32(allocID),
925 NetworkIntfId: int32(networkIntfID),
926 GemportId: int32(gemPortID),
927 Classifier: classifierProto,
928 Action: actionProto,
929 Priority: int32(logicalFlow.Priority),
930 Cookie: logicalFlow.Cookie,
931 PortNo: portNo}
932
David K. Bainbridge794735f2020-02-11 21:01:37 -0800933 if err := f.addFlowToDevice(ctx, logicalFlow, &flow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530934 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": flow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -0800935 }
936 log.Debugf("%s UL flow added to device successfully", flowType)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000937
David K. Bainbridge794735f2020-02-11 21:01:37 -0800938 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
939 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
940 flow.OnuId,
941 flow.UniId,
942 flow.FlowId, flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530943 return olterrors.NewErrPersistence("update", "flow", flow.FlowId, log.Fields{"flow": flow}, err).Log()
Esin Karamanae41e2b2019-12-17 18:13:13 +0000944 }
945
David K. Bainbridge794735f2020-02-11 21:01:37 -0800946 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +0000947}
948
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700949// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Girish Gowdrafae935c2020-02-17 19:21:44 +0530950func (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 -0700951 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 +0530952
953 uplinkClassifier := make(map[string]interface{})
954 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530955
manikkaraj kbf256be2019-03-25 00:13:48 +0530956 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700957 uplinkClassifier[EthType] = uint32(EapEthType)
958 uplinkClassifier[PacketTagType] = SingleTag
959 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530960 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700961 uplinkAction[TrapToHost] = true
962 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530963 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -0800964 log.Debug("Flow-exists-not-re-adding")
965 return nil
Girish Gowdra3d633032019-12-10 16:37:05 +0530966 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530967 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530968 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530969 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530970 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800971 "interface-id": intfID,
972 "onu-id": onuID,
973 "coookie": flowStoreCookie},
974 err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530975 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700976 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530977
David K. Bainbridge794735f2020-02-11 21:01:37 -0800978 classifierProto, err := makeOpenOltClassifierField(uplinkClassifier)
979 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530980 return olterrors.NewErrInvalidValue(log.Fields{"classifier": uplinkClassifier}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530981 }
982 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800983 actionProto, err := makeOpenOltActionField(uplinkAction)
984 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530985 return olterrors.NewErrInvalidValue(log.Fields{"action": uplinkAction}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +0530986 }
987 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -0800988 networkIntfID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530989 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +0530990 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -0800991 "classifier": classifier,
992 "action": action},
993 err).Log()
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530994 }
995
David K. Bainbridge794735f2020-02-11 21:01:37 -0800996 upstreamFlow := openoltpb2.Flow{AccessIntfId: int32(intfID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700997 OnuId: int32(onuID),
998 UniId: int32(uniID),
999 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001000 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001001 AllocId: int32(allocID),
1002 NetworkIntfId: int32(networkIntfID),
1003 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +05301004 Classifier: classifierProto,
1005 Action: actionProto,
1006 Priority: int32(logicalFlow.Priority),
1007 Cookie: logicalFlow.Cookie,
1008 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001009 if err := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301010 return olterrors.NewErrFlowOp("add", uplinkFlowID, log.Fields{"flow": upstreamFlow}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001011 }
1012 log.Debug("EAPOL UL flow added to device successfully")
1013 flowCategory := "EAPOL"
1014 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1015 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
1016 upstreamFlow.OnuId,
1017 upstreamFlow.UniId,
1018 upstreamFlow.FlowId,
1019 /* lowCategory, */
1020 flowsToKVStore); err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301021 return olterrors.NewErrPersistence("update", "flow", upstreamFlow.FlowId, log.Fields{"flow": upstreamFlow}, err).Log()
manikkaraj kbf256be2019-03-25 00:13:48 +05301022 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301023
manikkaraj kbf256be2019-03-25 00:13:48 +05301024 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001025 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301026}
1027
David K. Bainbridge794735f2020-02-11 21:01:37 -08001028func makeOpenOltClassifierField(classifierInfo map[string]interface{}) (*openoltpb2.Classifier, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001029 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001030
1031 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1032 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1033 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
Andrea Campanella7acc0b92020-02-14 09:20:49 +01001034 if vlanID != ReservedVlan {
1035 vid := vlanID & VlanvIDMask
Harsh Awasthiea45af72019-08-26 02:39:00 -04001036 classifier.OVid = vid
1037 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301038 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001039 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1040 vid := uint32(metadata)
1041 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001042 classifier.IVid = vid
1043 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301044 }
Girish Gowdrafae935c2020-02-17 19:21:44 +05301045 // Use VlanPCPMask (0xff) to signify NO PCP. Else use valid PCP (0 to 7)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001046 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Girish Gowdrafae935c2020-02-17 19:21:44 +05301047 classifier.OPbits = vlanPcp
1048 } else {
1049 classifier.OPbits = VlanPCPMask
manikkaraj kbf256be2019-03-25 00:13:48 +05301050 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001051 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1052 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1053 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1054 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001055 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001056 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1057 classifier.PktTagType = pktTagType
1058
1059 switch pktTagType {
1060 case SingleTag:
1061 case DoubleTag:
1062 case Untagged:
1063 default:
Girish Kumarf26e4882020-03-05 06:49:10 +00001064 return nil, olterrors.NewErrInvalidValue(log.Fields{"packet-tag-type": pktTagType}, nil)
manikkaraj kbf256be2019-03-25 00:13:48 +05301065 }
1066 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001067 return &classifier, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301068}
1069
David K. Bainbridge794735f2020-02-11 21:01:37 -08001070func makeOpenOltActionField(actionInfo map[string]interface{}) (*openoltpb2.Action, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001071 var actionCmd openoltpb2.ActionCmd
1072 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301073 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001074 if _, ok := actionInfo[PopVlan]; ok {
1075 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301076 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001077 } else if _, ok := actionInfo[PushVlan]; ok {
1078 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301079 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001080 } else if _, ok := actionInfo[TrapToHost]; ok {
1081 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301082 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00001083 return nil, olterrors.NewErrInvalidValue(log.Fields{"action-command": actionInfo}, nil)
manikkaraj kbf256be2019-03-25 00:13:48 +05301084 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001085 return &action, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301086}
1087
Manikkaraj kb1d51442019-07-23 10:41:02 -04001088func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1089 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301090}
1091
Gamze Abakafee36392019-10-03 11:17:24 +00001092// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301093func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1094 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001095 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001096 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301097 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001098 olterrors.NewErrAdapter("delete-tech-profile-failed", nil, err).Log()
Girish Gowdra54934262019-11-13 14:19:55 +05301099 // return err
1100 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001101 }
1102 }
1103 return nil
1104}
1105
1106// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301107func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001108 if uniPortName == "" {
1109 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1110 }
npujarec5762e2020-01-01 14:08:48 +05301111 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001112 return olterrors.NewErrAdapter("failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName}, err)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001113 }
1114 return nil
1115}
1116
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001117func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301118 if len(classifier) == 0 { // should never happen
1119 log.Error("Invalid classfier object")
1120 return 0
1121 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301122 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301123 var jsonData []byte
1124 var flowString string
1125 var err error
1126 // TODO: Do we need to marshall ??
1127 if jsonData, err = json.Marshal(classifier); err != nil {
1128 log.Error("Failed to encode classifier")
1129 return 0
1130 }
1131 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001132 if gemPortID != 0 {
1133 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301134 }
1135 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001136 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301137 hash := big.NewInt(0)
1138 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301139 generatedHash := hash.Uint64()
1140 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1141 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301142}
1143
npujarec5762e2020-01-01 14:08:48 +05301144func (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 +05301145 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001146 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001147 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1148 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1149 */
1150 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001151 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001152 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001153 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001154 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001155 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301156 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001157 if existingFlows != nil {
1158 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001159 //for _, f := range *existingFlows {
1160 // flows = append(flows, f)
1161 //}
1162 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001163 }
1164 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 +05301165 return &flows
1166}
1167
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001168//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1169// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1170// var intfId uint32
1171// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1172// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1173// */
1174// if flow.AccessIntfId != -1 {
1175// intfId = uint32(flow.AccessIntfId)
1176// } else {
1177// intfId = uint32(flow.NetworkIntfId)
1178// }
1179// // Get existing flows matching flowid for given subscriber from KV store
1180// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1181// if existingFlows != nil {
1182// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1183// for _, f := range *existingFlows {
1184// flows = append(flows, f)
1185// }
1186// }
1187// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1188// return &flows
1189//}
1190
npujarec5762e2020-01-01 14:08:48 +05301191func (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 -04001192 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301193 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001194 log.Debug("Error while Storing flow into KV store")
1195 return err
1196 }
1197 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301198 return nil
1199}
1200
David K. Bainbridge794735f2020-02-11 21:01:37 -08001201func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) error {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001202
1203 var intfID uint32
1204 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1205 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1206 */
1207 if deviceFlow.AccessIntfId != -1 {
1208 intfID = uint32(deviceFlow.AccessIntfId)
1209 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001210 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001211 intfID = uint32(deviceFlow.NetworkIntfId)
1212 }
1213
manikkaraj kbf256be2019-03-25 00:13:48 +05301214 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1215 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001216
1217 st, _ := status.FromError(err)
1218 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001219 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001220 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301221 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001222
1223 if err != nil {
1224 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301225 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001226 return err
Daniele Rossi22db98e2019-07-11 11:50:00 +00001227 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301228 if deviceFlow.GemportId != -1 {
1229 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301230 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301231 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301232 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001233 return nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001234}
1235
David K. Bainbridge794735f2020-02-11 21:01:37 -08001236func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001237 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1238 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1239 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001240 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1241 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1242 //Assume the flow is removed
David K. Bainbridge794735f2020-02-11 21:01:37 -08001243 return nil
serkant.uluderya245caba2019-09-24 23:15:29 -07001244 }
Girish Kumarf26e4882020-03-05 06:49:10 +00001245 return olterrors.NewErrFlowOp("remove", deviceFlow.FlowId, log.Fields{"deviceFlow": deviceFlow}, err)
serkant.uluderya245caba2019-09-24 23:15:29 -07001246
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001247 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001248 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001249 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301250}
1251
1252/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1253 //update core flows_proxy : flows_proxy.update('/', flows)
1254}
1255
1256func generateStoredId(flowId uint32, direction string)uint32{
1257
David K. Bainbridge82efc492019-09-04 09:57:11 -07001258 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301259 log.Debug("Upstream flow shifting flowid")
1260 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001261 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301262 log.Debug("Downstream flow not shifting flowid")
1263 return flowId
1264 }else{
1265 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1266 return flowId
1267 }
1268}
1269
1270*/
1271
David K. Bainbridge794735f2020-02-11 21:01:37 -08001272func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) error {
Humera Kouser94d7a842019-08-25 19:04:32 -04001273
1274 classifierInfo := make(map[string]interface{})
1275 actionInfo := make(map[string]interface{})
1276
1277 classifierInfo[EthType] = uint32(LldpEthType)
1278 classifierInfo[PacketTagType] = Untagged
1279 actionInfo[TrapToHost] = true
1280
1281 // LLDP flow is installed to trap LLDP packets on the NNI port.
1282 // We manage flow_id resource pool on per PON port basis.
1283 // Since this situation is tricky, as a hack, we pass the NNI port
1284 // index (network_intf_id) as PON port Index for the flow_id resource
1285 // pool. Also, there is no ONU Id available for trapping LLDP packets
1286 // on NNI port, use onu_id as -1 (invalid)
1287 // ****************** CAVEAT *******************
1288 // This logic works if the NNI Port Id falls within the same valid
1289 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1290 // we need to have a re-look at this.
1291 // *********************************************
1292
1293 var onuID = -1
1294 var uniID = -1
1295 var gemPortID = -1
1296
David K. Bainbridge794735f2020-02-11 21:01:37 -08001297 networkInterfaceID, err := IntfIDFromNniPortNum(portNo)
1298 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301299 return olterrors.NewErrInvalidValue(log.Fields{"nni-port-number": portNo}, err).Log()
David K. Bainbridge794735f2020-02-11 21:01:37 -08001300 }
Humera Kouser94d7a842019-08-25 19:04:32 -04001301 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301302 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001303 log.Debug("Flow-exists--not-re-adding")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001304 return nil
Humera Kouser94d7a842019-08-25 19:04:32 -04001305 }
npujarec5762e2020-01-01 14:08:48 +05301306 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001307
1308 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301309 return olterrors.NewErrNotFound("flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001310 "interface-id": networkInterfaceID,
1311 "onu-id": onuID,
1312 "uni-id": uniID,
1313 "gem-port-id": gemPortID,
1314 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00001315 err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001316 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001317 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1318 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001319 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001320 }
1321 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001322 actionProto, err := makeOpenOltActionField(actionInfo)
1323 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001324 return olterrors.NewErrInvalidValue(log.Fields{"action": actionInfo}, err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001325 }
1326 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1327
1328 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1329 OnuId: int32(onuID), // OnuId not required
1330 UniId: int32(uniID), // UniId not used
1331 FlowId: flowID,
1332 FlowType: Downstream,
1333 NetworkIntfId: int32(networkInterfaceID),
1334 GemportId: int32(gemPortID),
1335 Classifier: classifierProto,
1336 Action: actionProto,
1337 Priority: int32(flow.Priority),
1338 Cookie: flow.Cookie,
1339 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08001340 if err := f.addFlowToDevice(ctx, flow, &downstreamflow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001341 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err)
Humera Kouser94d7a842019-08-25 19:04:32 -04001342 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001343 log.Debug("LLDP trap on NNI flow added to device successfully")
1344 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1345 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1346 int32(onuID),
1347 int32(uniID),
1348 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001349 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001350 }
1351 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301352}
1353
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301354func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001355 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1356}
1357
1358//getOnuChildDevice to fetch onu
1359func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1360 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1361 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001362 onuDevice, err := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
1363 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301364 return nil, olterrors.NewErrNotFound("onu", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001365 "interface-id": parentPortNo,
1366 "onu-id": onuID},
Girish Kumarf26e4882020-03-05 06:49:10 +00001367 err)
manikkaraj kbf256be2019-03-25 00:13:48 +05301368 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301369 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1370 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301371}
1372
1373func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001374 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301375 return nil
1376}
1377
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001378func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1379 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301380}
1381
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001382func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001383 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001384 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001385 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001386 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001387}
1388
Girish Gowdra6b130582019-11-20 16:45:20 +05301389func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1390 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1391 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001392 return olterrors.NewErrNotFound("onu-child-device", log.Fields{"onuId": onuID, "intfID": intfID}, err)
Girish Gowdra6b130582019-11-20 16:45:20 +05301393 }
1394
1395 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1396 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1397 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1398 delGemPortMsg,
1399 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1400 f.deviceHandler.deviceType,
1401 onuDevice.Type,
1402 onuDevice.Id,
1403 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001404 return olterrors.NewErrCommunication("send-delete-gem-port-to-onu-adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
Girish Gowdra6b130582019-11-20 16:45:20 +05301405 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
Girish Kumarf26e4882020-03-05 06:49:10 +00001406 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId}, sendErr)
Girish Gowdra6b130582019-11-20 16:45:20 +05301407 }
1408 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1409 return nil
1410}
1411
1412func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1413 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1414 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001415 return olterrors.NewErrNotFound("onu-child-device", log.Fields{"onuId": onuID, "intfID": intfID}, err)
Girish Gowdra6b130582019-11-20 16:45:20 +05301416 }
1417
1418 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1419 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1420 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1421 delTcontMsg,
1422 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1423 f.deviceHandler.deviceType,
1424 onuDevice.Type,
1425 onuDevice.Id,
1426 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001427 return olterrors.NewErrCommunication("send-delete-tcont-to-onu-adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
Girish Gowdra6b130582019-11-20 16:45:20 +05301428 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
Girish Kumarf26e4882020-03-05 06:49:10 +00001429 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId}, sendErr)
Girish Gowdra6b130582019-11-20 16:45:20 +05301430 }
1431 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1432 return nil
1433}
1434
Girish Gowdra3d633032019-12-10 16:37:05 +05301435func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1436 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1437 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1438 if val.(int) > 0 {
1439 pnFlDels := val.(int) - 1
1440 if pnFlDels > 0 {
1441 log.Debugw("flow delete succeeded, more pending",
1442 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1443 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1444 } else {
1445 log.Debugw("all pending flow deletes handled, removing entry from map",
1446 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1447 f.pendingFlowDelete.Delete(pnFlDelKey)
1448 }
1449 }
1450 } else {
1451 log.Debugw("no pending delete flows found",
1452 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1453
1454 }
1455
1456}
1457
Girish Gowdrac3037402020-01-22 20:29:53 +05301458// Once the gemport is released for a given onu, it also has to be cleared from local cache
1459// which was used for deriving the gemport->logicalPortNo during packet-in.
1460// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1461// is conveyed to ONOS during packet-in OF message.
1462func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1463 f.lockCache.Lock()
1464 defer f.lockCache.Unlock()
1465 onugem := f.onuGemInfo[intfID]
serkant.uluderya96af4932020-02-20 16:58:48 -08001466 for i, onu := range onugem {
Girish Gowdrac3037402020-01-22 20:29:53 +05301467 if onu.OnuID == onuID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001468 for j, gem := range onu.GemPorts {
Girish Gowdrac3037402020-01-22 20:29:53 +05301469 // If the gemport is found, delete it from local cache.
1470 if gem == gemPortID {
serkant.uluderya96af4932020-02-20 16:58:48 -08001471 onu.GemPorts = append(onu.GemPorts[:j], onu.GemPorts[j+1:]...)
1472 onugem[i] = onu
Girish Gowdrac3037402020-01-22 20:29:53 +05301473 log.Debugw("removed gemport from local cache",
serkant.uluderya96af4932020-02-20 16:58:48 -08001474 log.Fields{"intfID": intfID, "onuID": onuID, "deletedGemPortID": gemPortID, "gemPorts": onu.GemPorts})
Girish Gowdrac3037402020-01-22 20:29:53 +05301475 break
1476 }
1477 }
1478 break
1479 }
1480 }
1481}
1482
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301483//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301484func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301485 gemPortID int32, flowID uint32, flowDirection string,
1486 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001487
Chaitrashree G S90a17952019-11-14 21:51:21 -05001488 tpID, err := getTpIDFromFlow(flow)
1489 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001490 return olterrors.NewErrNotFound("tpid", log.Fields{"flow": flow, "pon": Intf, "onuID": onuID, "uniID": uniID}, err)
Chaitrashree G S90a17952019-11-14 21:51:21 -05001491 }
Gamze Abakafee36392019-10-03 11:17:24 +00001492
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001493 if len(updatedFlows) >= 0 {
1494 // There are still flows referencing the same flow_id.
1495 // So the flow should not be freed yet.
1496 // For ex: Case of HSIA where same flow is shared
1497 // between DS and US.
Girish Kumarf26e4882020-03-05 06:49:10 +00001498 if err := f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows); err != nil {
1499 olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": updatedFlows}, err).Log()
1500 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001501 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301502 // Do this for subscriber flows only (not trap from NNI flows)
1503 if onuID != -1 && uniID != -1 {
1504 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1505 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1506 log.Debugw("creating entry for pending flow delete",
1507 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1508 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1509 } else {
1510 pnFlDels := val.(int) + 1
1511 log.Debugw("updating flow delete entry",
1512 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1513 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1514 }
1515
1516 defer f.deletePendingFlows(Intf, onuID, uniID)
1517 }
1518
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301519 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301520 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001521
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301522 uni := getUniPortPath(Intf, onuID, uniID)
1523 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001524 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301525 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Girish Kumarf26e4882020-03-05 06:49:10 +00001526 if err != nil || techprofileInst == nil { // This should not happen, something wrong in KV backend transaction
1527 return olterrors.NewErrNotFound("tech-profile-in-kv-store", log.Fields{"tpID": tpID, "path": tpPath}, err)
Gamze Abakafee36392019-10-03 11:17:24 +00001528 }
1529
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301530 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001531 if f.isGemPortUsedByAnotherFlow(gemPK) {
1532 flowIDs := f.flowsUsedByGemPort[gemPK]
1533 for i, flowIDinMap := range flowIDs {
1534 if flowIDinMap == flowID {
1535 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301536 // everytime flowsUsedByGemPort cache is updated the same should be updated
1537 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001538 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301539 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001540 break
1541 }
1542 }
1543 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301544 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001545 }
Gamze Abakafee36392019-10-03 11:17:24 +00001546 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301547 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001548 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1549 // 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 +05301550 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301551 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001552 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301553 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1554 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001555 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301556 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1557 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001558 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301559 // Delete the gem port on the ONU.
1560 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1561 log.Errorw("error processing delete gem-port towards onu",
1562 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1563 }
Gamze Abakafee36392019-10-03 11:17:24 +00001564
npujarec5762e2020-01-01 14:08:48 +05301565 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001566 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301567 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1568 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1569 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1570 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1571 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301572 // Delete the TCONT on the ONU.
1573 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1574 log.Errorw("error processing delete tcont towards onu",
1575 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1576 }
Gamze Abakafee36392019-10-03 11:17:24 +00001577 }
1578 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001579 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301580 return nil
1581}
1582
David K. Bainbridge794735f2020-02-11 21:01:37 -08001583// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301584func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301585
1586 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001587
1588 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301589 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001590 return
1591 }
1592
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301593 var updatedFlows []rsrcMgr.FlowInfo
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301594 classifierInfo := make(map[string]interface{})
1595
1596 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1597 if err != nil {
1598 log.Error(err)
1599 return
1600 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301601
David K. Bainbridge794735f2020-02-11 21:01:37 -08001602 onuID := int32(onu)
1603 uniID := int32(uni)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301604
1605 for _, field := range flows.GetOfbFields(flow) {
1606 if field.Type == flows.IP_PROTO {
1607 classifierInfo[IPProto] = field.GetIpProto()
1608 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1609 }
1610 }
1611 log.Debugw("Extracted access info from flow to be deleted",
1612 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1613
1614 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1615 onuID = -1
1616 uniID = -1
1617 log.Debug("Trap on nni flow set oni, uni to -1")
David K. Bainbridge794735f2020-02-11 21:01:37 -08001618 Intf, err = IntfIDFromNniPortNum(inPort)
1619 if err != nil {
1620 log.Errorw("invalid-in-port-number",
1621 log.Fields{
1622 "port-number": inPort,
1623 "error": err})
1624 return
1625 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301626 }
npujarec5762e2020-01-01 14:08:48 +05301627 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001628 for _, flowID := range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301629 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301630 if flowInfo == nil {
1631 log.Debugw("No FlowInfo found found in KV store",
1632 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1633 return
1634 }
1635 updatedFlows = nil
1636 for _, flow := range *flowInfo {
1637 updatedFlows = append(updatedFlows, flow)
1638 }
1639
1640 for i, storedFlow := range updatedFlows {
1641 if flow.Id == storedFlow.LogicalFlowID {
1642 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1643 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
David K. Bainbridge794735f2020-02-11 21:01:37 -08001644 // DKB
1645 if err = f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1646 log.Errorw("failed-to-remove-flow", log.Fields{"error": err})
1647 return
1648 }
1649 log.Debug("Flow removed from device successfully")
1650 //Remove the Flow from FlowInfo
1651 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1652 if err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1653 flowID, flowDirection, portNum, updatedFlows); err != nil {
1654 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301655 return
1656 }
1657 }
1658 }
1659 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001660}
1661
Esin Karamanccb714b2019-11-29 15:02:06 +00001662//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1663// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301664func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001665 classifierInfo := make(map[string]interface{})
1666 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301667 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001668
1669 if err != nil {
1670 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1671 return
1672 }
1673
David K. Bainbridge794735f2020-02-11 21:01:37 -08001674 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1675 if err != nil {
1676 // DKB
1677 log.Errorw("invalid-in-port-number",
1678 log.Fields{
1679 "port-number": inPort,
1680 "error": err})
1681 return
1682 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001683 var onuID = int32(NoneOnuID)
1684 var uniID = int32(NoneUniID)
1685 var flowID uint32
1686 var updatedFlows []rsrcMgr.FlowInfo
1687
npujarec5762e2020-01-01 14:08:48 +05301688 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001689
1690 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301691 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001692 if flowInfo == nil {
1693 log.Debugw("No multicast FlowInfo found in the KV store",
1694 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1695 continue
1696 }
1697 updatedFlows = nil
1698 for _, flow := range *flowInfo {
1699 updatedFlows = append(updatedFlows, flow)
1700 }
1701 for i, storedFlow := range updatedFlows {
1702 if flow.Id == storedFlow.LogicalFlowID {
1703 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1704 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1705 //remove from device
David K. Bainbridge794735f2020-02-11 21:01:37 -08001706 if err := f.removeFlowFromDevice(&removeFlowMessage); err != nil {
1707 // DKB
1708 log.Errorw("failed-to-remove-multicast-flow",
1709 log.Fields{
1710 "flow-id": flow.Id,
1711 "error": err})
Esin Karamanccb714b2019-11-29 15:02:06 +00001712 return
1713 }
1714 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1715 //Remove the Flow from FlowInfo
1716 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301717 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001718 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1719 return
1720 }
1721 //release flow id
1722 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301723 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001724 }
1725 }
1726 }
1727}
1728
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001729//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301730func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001731 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301732 var direction string
1733 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001734
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301735 for _, action := range flows.GetActions(flow) {
1736 if action.Type == flows.OUTPUT {
1737 if out := action.GetOutput(); out != nil {
1738 actionInfo[Output] = out.GetPort()
1739 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1740 } else {
1741 log.Error("Invalid output port in action")
1742 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001743 }
1744 }
1745 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001746
1747 if flows.HasGroup(flow) {
1748 direction = Multicast
1749 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301750 direction = Upstream
1751 } else {
1752 direction = Downstream
1753 }
npujarec5762e2020-01-01 14:08:48 +05301754 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301755
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001756 return
1757}
1758
Girish Gowdra3d633032019-12-10 16:37:05 +05301759func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1760 uniID uint32, ch chan bool) {
1761 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1762 for {
1763 select {
1764 case <-time.After(20 * time.Millisecond):
1765 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1766 log.Debug("pending flow deletes completed")
1767 ch <- true
1768 return
1769 }
1770 case <-ctx.Done():
1771 log.Error("flow delete wait handler routine canceled")
1772 return
1773 }
1774 }
1775}
1776
Esin Karamanae41e2b2019-12-17 18:13:13 +00001777//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1778func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1779 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1780 if ethType, ok := classifierInfo[EthType]; ok {
1781 if ethType.(uint32) == IPv4EthType {
1782 if ipProto, ok := classifierInfo[IPProto]; ok {
1783 if ipProto.(uint32) == IgmpProto {
1784 return true
1785 }
1786 }
1787 }
1788 }
1789 }
1790 return false
1791}
1792
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001793// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301794// nolint: gocyclo
Andrea Campanellac63bba92020-03-10 17:01:04 +01001795func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001796 classifierInfo := make(map[string]interface{})
1797 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001798 var UsMeterID uint32
1799 var DsMeterID uint32
1800
1801 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001802 formulateClassifierInfoFromFlow(classifierInfo, flow)
1803
1804 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1805 if err != nil {
1806 // Error logging is already done in the called function
1807 // So just return in case of error
Andrea Campanellac63bba92020-03-10 17:01:04 +01001808 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05301809 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001810
Esin Karamanccb714b2019-11-29 15:02:06 +00001811 if flows.HasGroup(flow) {
1812 // handle multicast flow
Andrea Campanellac63bba92020-03-10 17:01:04 +01001813 return f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001814 }
1815
manikkaraj k17652a72019-05-06 09:06:36 -04001816 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001817 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1818 if err != nil {
1819 // error if any, already logged in the called function
Andrea Campanellac63bba92020-03-10 17:01:04 +01001820 return err
manikkaraj k17652a72019-05-06 09:06:36 -04001821 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001822
David K. Bainbridge82efc492019-09-04 09:57:11 -07001823 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1824 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001825
Humera Kouser94d7a842019-08-25 19:04:32 -04001826 if ethType, ok := classifierInfo[EthType]; ok {
1827 if ethType.(uint32) == LldpEthType {
1828 log.Info("Adding LLDP flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001829 return f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001830 }
1831 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001832 if ipProto, ok := classifierInfo[IPProto]; ok {
1833 if ipProto.(uint32) == IPProtoDhcp {
1834 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301835 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001836 log.Debug("trap-dhcp-from-nni-flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001837 return f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001838 }
1839 }
1840 }
1841 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001842 if isIgmpTrapDownstreamFlow(classifierInfo) {
1843 log.Debug("trap-igmp-from-nni-flow")
Andrea Campanellac63bba92020-03-10 17:01:04 +01001844 return f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001845 }
A R Karthick1f85b802019-10-11 05:06:05 +00001846
1847 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301848 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001849
Chaitrashree G S90a17952019-11-14 21:51:21 -05001850 TpID, err := getTpIDFromFlow(flow)
1851 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001852 return olterrors.NewErrNotFound("tpid-for-flow", log.Fields{"flow": flow, "pon": IntfID, "onuID": onuID, "uniID": uniID}, err)
Chaitrashree G S90a17952019-11-14 21:51:21 -05001853 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001854 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001855 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001856 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001857 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1858 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001859 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001860 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1861
1862 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301863
1864 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1865 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1866 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 +05301867 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301868 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301869 pendingFlowDelComplete := make(chan bool)
1870 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1871 select {
1872 case <-pendingFlowDelComplete:
1873 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301874 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301875
1876 case <-time.After(10 * time.Second):
Girish Kumarf26e4882020-03-05 06:49:10 +00001877 return olterrors.NewErrTimeout("pending-flow-deletes", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID}, nil)
Girish Gowdra3d633032019-12-10 16:37:05 +05301878 }
1879 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01001880 return nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001881}
1882
Esin Karamanccb714b2019-11-29 15:02:06 +00001883// handleFlowWithGroup adds multicast flow to the device.
David K. Bainbridge794735f2020-02-11 21:01:37 -08001884func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001885 classifierInfo[PacketTagType] = DoubleTag
1886 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1887
npujarec5762e2020-01-01 14:08:48 +05301888 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001889 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001890 return olterrors.NewErrNotFound("multicast-in-port", log.Fields{"classifier": classifierInfo}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001891 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001892 //this variable acts like a switch. When it is set, multicast flows are classified by eth_dst.
1893 //otherwise, classification is based on ipv4_dst by default.
1894 //the variable can be configurable in the future; it can be read from a configuration path in the kv store.
1895 mcastFlowClassificationByEthDst := false
1896
1897 if mcastFlowClassificationByEthDst {
1898 //replace ipDst with ethDst
1899 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1900 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1901 // replace ipv4_dst classifier with eth_dst
1902 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1903 delete(classifierInfo, Ipv4Dst)
1904 classifierInfo[EthDst] = multicastMac
1905 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1906 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001907 }
Esin Karamanfcddfcf2020-03-04 13:34:38 +00001908 delete(classifierInfo, EthType)
Esin Karamanccb714b2019-11-29 15:02:06 +00001909
David K. Bainbridge794735f2020-02-11 21:01:37 -08001910 onuID := NoneOnuID
1911 uniID := NoneUniID
1912 gemPortID := NoneGemPortID
Esin Karamanccb714b2019-11-29 15:02:06 +00001913
David K. Bainbridge794735f2020-02-11 21:01:37 -08001914 networkInterfaceID, err := IntfIDFromNniPortNum(inPort)
1915 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001916 return olterrors.NewErrInvalidValue(log.Fields{"nni-in-port-number": inPort}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001917 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001918
David K. Bainbridge794735f2020-02-11 21:01:37 -08001919 flowStoreCookie := getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301920 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001921 log.Debugw("multicast-flow-exists-not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1922 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001923 }
npujarec5762e2020-01-01 14:08:48 +05301924 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001925 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05301926 return olterrors.NewErrNotFound("multicast-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08001927 "interface-id": networkInterfaceID,
1928 "onu-id": onuID,
1929 "uni-id": uniID,
1930 "gem-port-id": gemPortID,
1931 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00001932 err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001933 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001934 classifierProto, err := makeOpenOltClassifierField(classifierInfo)
1935 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001936 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifierInfo}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001937 }
1938 groupID := actionInfo[GroupID].(uint32)
1939 multicastFlow := openoltpb2.Flow{
1940 FlowId: flowID,
1941 FlowType: Multicast,
1942 NetworkIntfId: int32(networkInterfaceID),
1943 GroupId: groupID,
1944 Classifier: classifierProto,
1945 Priority: int32(flow.Priority),
1946 Cookie: flow.Cookie}
1947
David K. Bainbridge794735f2020-02-11 21:01:37 -08001948 if err = f.addFlowToDevice(ctx, flow, &multicastFlow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001949 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": multicastFlow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001950 }
1951 log.Debug("multicast flow added to device successfully")
1952 //get cached group
1953 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
1954 if err == nil {
1955 //calling groupAdd to set group members after multicast flow creation
Andrea Campanellac63bba92020-03-10 17:01:04 +01001956 if err = f.ModifyGroup(ctx, group); err == nil {
David K. Bainbridge794735f2020-02-11 21:01:37 -08001957 //cached group can be removed now
1958 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Andrea Campanellac63bba92020-03-10 17:01:04 +01001959 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00001960 return olterrors.NewErrGroupOp("modify", groupID, log.Fields{"group": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00001961 }
1962 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08001963
1964 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1965 if err = f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
1966 int32(onuID),
1967 int32(uniID),
1968 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001969 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": multicastFlow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08001970 }
1971 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00001972}
1973
1974//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301975func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001976 if _, ok := classifierInfo[InPort]; ok {
1977 return classifierInfo[InPort].(uint32), nil
1978 }
1979 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301980 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001981 if e == nil && len(nniPorts) > 0 {
1982 return nniPorts[0], nil
1983 }
Thomas Lee S94109f12020-03-03 16:39:29 +05301984 return 0, olterrors.NewErrNotFound("nni-port", nil, e).Log()
Esin Karamanccb714b2019-11-29 15:02:06 +00001985}
1986
1987// AddGroup add or update the group
Andrea Campanellac63bba92020-03-10 17:01:04 +01001988func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00001989 log.Infow("add-group", log.Fields{"group": group})
1990 if group == nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00001991 return olterrors.NewErrInvalidValue(log.Fields{"group": group}, nil)
Esin Karamanccb714b2019-11-29 15:02:06 +00001992 }
1993
1994 groupToOlt := openoltpb2.Group{
1995 GroupId: group.Desc.GroupId,
1996 Command: openoltpb2.Group_SET_MEMBERS,
1997 Action: f.buildGroupAction(),
1998 }
1999
2000 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05302001 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002002 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002003 return olterrors.NewErrAdapter("add-group-operation-failed", log.Fields{"groupToOlt": groupToOlt}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002004 }
2005 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05302006 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002007 return olterrors.NewErrPersistence("add", "flow-group", group.Desc.GroupId, log.Fields{"group": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002008 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002009 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
2010 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002011}
2012
2013//buildGroupAction creates and returns a group action
2014func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
2015 var actionCmd openoltpb2.ActionCmd
2016 var action openoltpb2.Action
2017 action.Cmd = &actionCmd
2018 //pop outer vlan
2019 action.Cmd.RemoveOuterTag = true
2020 return &action
2021}
2022
2023// ModifyGroup updates the group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002024func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002025 log.Infow("modify-group", log.Fields{"group": group})
2026 if group == nil || group.Desc == nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002027 return olterrors.NewErrInvalidValue(log.Fields{"group": group, "groupDesc": group.Desc}, nil)
Esin Karamanccb714b2019-11-29 15:02:06 +00002028 }
2029
Andrea Campanellac63bba92020-03-10 17:01:04 +01002030 newGroup := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
Esin Karamanccb714b2019-11-29 15:02:06 +00002031 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302032 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002033
2034 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002035 return olterrors.NewErrNotFound("flow-group-in-kv-store", log.Fields{"groupId": group.Desc.GroupId}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002036 }
2037
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002038 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002039 if groupExists {
2040 // group already exists
2041 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002042 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002043 } else {
2044 current = f.buildGroup(group.Desc.GroupId, nil)
2045 }
2046
Andrea Campanellac63bba92020-03-10 17:01:04 +01002047 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": newGroup})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002048 // get members to be added
Andrea Campanellac63bba92020-03-10 17:01:04 +01002049 membersToBeAdded := f.findDiff(current, newGroup)
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002050 // get members to be removed
Andrea Campanellac63bba92020-03-10 17:01:04 +01002051 membersToBeRemoved := f.findDiff(newGroup, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002052
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002053 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2054 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002055
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002056 groupToOlt := openoltpb2.Group{
2057 GroupId: group.Desc.GroupId,
2058 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002059 var errAdd, errRemoved error
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002060 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2061 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2062 groupToOlt.Members = membersToBeAdded
2063 //execute addMembers
Andrea Campanellac63bba92020-03-10 17:01:04 +01002064 errAdd = f.callGroupAddRemove(&groupToOlt)
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002065 }
2066 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2067 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2068 groupToOlt.Members = membersToBeRemoved
2069 //execute removeMembers
Andrea Campanellac63bba92020-03-10 17:01:04 +01002070 errRemoved = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002071 }
2072
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002073 //save the modified group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002074 if errAdd == nil && errRemoved == nil {
npujarec5762e2020-01-01 14:08:48 +05302075 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002076 return olterrors.NewErrPersistence("add", "flow-group", group.Desc.GroupId, log.Fields{"group": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002077 }
2078 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002079 } else {
2080 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2081 log.Fields{"group": group})
Andrea Campanellac63bba92020-03-10 17:01:04 +01002082 if errAdd != nil {
2083 return errAdd
2084 }
2085 return errRemoved
Esin Karamanccb714b2019-11-29 15:02:06 +00002086 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002087 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002088}
2089
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002090//callGroupAddRemove performs add/remove buckets operation for the indicated group
Andrea Campanellac63bba92020-03-10 17:01:04 +01002091func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) error {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002092 if err := f.performGroupOperation(group); err != nil {
2093 st, _ := status.FromError(err)
2094 //ignore already exists error code
2095 if st.Code() != codes.AlreadyExists {
Andrea Campanellac63bba92020-03-10 17:01:04 +01002096 return olterrors.NewErrGroupOp("groupAddRemove", group.GroupId, log.Fields{"status": st}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002097 }
2098 }
Andrea Campanellac63bba92020-03-10 17:01:04 +01002099 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002100}
2101
2102//findDiff compares group members and finds members which only exists in groups2
2103func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2104 var members []*openoltpb2.GroupMember
2105 for _, bucket := range group2.Members {
2106 if !f.contains(group1.Members, bucket) {
2107 // bucket does not exist and must be added
2108 members = append(members, bucket)
2109 }
2110 }
2111 return members
2112}
2113
2114//contains returns true if the members list contains the given member; false otherwise
2115func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2116 for _, groupMember := range members {
2117 if groupMember.InterfaceId == member.InterfaceId {
2118 return true
2119 }
2120 }
2121 return false
2122}
2123
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002124//performGroupOperation call performGroupOperation operation of openolt proto
2125func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002126 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2127 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2128 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002129 return olterrors.NewErrAdapter("group-operation-failed", log.Fields{"groupToOlt": group}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00002130 }
Girish Kumarf26e4882020-03-05 06:49:10 +00002131 return nil
Esin Karamanccb714b2019-11-29 15:02:06 +00002132}
2133
2134//buildGroup build openoltpb2.Group from given group id and bucket list
2135func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2136 group := openoltpb2.Group{
2137 GroupId: groupID}
2138 // create members of the group
2139 if buckets != nil {
2140 for _, ofBucket := range buckets {
2141 member := f.buildMember(ofBucket)
2142 if member != nil && !f.contains(group.Members, member) {
2143 group.Members = append(group.Members, member)
2144 }
2145 }
2146 }
2147 return &group
2148}
2149
2150//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2151func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2152 var outPort uint32
2153 outPortFound := false
2154 for _, ofAction := range ofBucket.Actions {
2155 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2156 outPort = ofAction.GetOutput().Port
2157 outPortFound = true
2158 }
2159 }
2160
2161 if !outPortFound {
2162 log.Debugw("bucket skipped since no out port found in it",
2163 log.Fields{"ofBucket": ofBucket})
2164 return nil
2165 }
2166 interfaceID := IntfIDFromUniPortNum(outPort)
2167 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2168 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2169 member := openoltpb2.GroupMember{
2170 InterfaceId: interfaceID,
2171 InterfaceType: openoltpb2.GroupMember_PON,
2172 GemPortId: groupInfo.gemPortID,
2173 Priority: groupInfo.servicePriority,
2174 }
2175 //add member to the group
2176 return &member
2177 }
2178 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2179 log.Fields{"ofBucket": ofBucket})
2180 return nil
2181}
2182
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002183//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002184func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002185
2186 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302187 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002188 return olterrors.NewErrNotFound("onu-child-device", log.Fields{"onuId": onuID, "intfID": intfID}, err)
manikkaraj kbf256be2019-03-25 00:13:48 +05302189 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302190 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002191
Manikkaraj kb1d51442019-07-23 10:41:02 -04002192 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002193 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002194 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2195 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2196 tpDownloadMsg,
2197 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2198 f.deviceHandler.deviceType,
2199 onuDevice.Type,
2200 onuDevice.Id,
2201 onuDevice.ProxyAddress.DeviceId, "")
2202 if sendErr != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002203 return olterrors.NewErrCommunication("send-techprofile-download-request", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
manikkaraj k17652a72019-05-06 09:06:36 -04002204 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
Girish Kumarf26e4882020-03-05 06:49:10 +00002205 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId}, sendErr)
manikkaraj k17652a72019-05-06 09:06:36 -04002206 }
2207 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302208 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302209}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002210
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302211//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302212func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302213
2214 f.lockCache.Lock()
2215 defer f.lockCache.Unlock()
2216 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2217 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
Chaitrashree G S1a55b882020-02-04 17:35:35 -05002218 if err := f.resourceMgr.AddOnuGemInfo(ctx, intfID, onu); err != nil {
2219 // TODO: VOL-2638
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302220 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2221 return
2222 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002223 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2224}
2225
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302226//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302227func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302228 f.lockCache.Lock()
2229 defer f.lockCache.Unlock()
2230 onugem := f.onuGemInfo[intfID]
2231 // update the gem to the local cache as well as to kv strore
2232 for idx, onu := range onugem {
2233 if onu.OnuID == onuID {
2234 // check if gem already exists , else update the cache and kvstore
2235 for _, gem := range onu.GemPorts {
2236 if gem == gemPort {
2237 log.Debugw("Gem already in cache, no need to update cache and kv store",
2238 log.Fields{"gem": gemPort})
2239 return
2240 }
2241 }
2242 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2243 f.onuGemInfo[intfID] = onugem
2244 }
2245 }
npujarec5762e2020-01-01 14:08:48 +05302246 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302247 if err != nil {
2248 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002249 return
2250 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002251}
2252
2253// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002254
2255//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2256func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302257
2258 f.lockCache.Lock()
2259 defer f.lockCache.Unlock()
2260
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002261 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 +05302262 // get onuid from the onugem info cache
2263 onugem := f.onuGemInfo[intfID]
2264 for _, onu := range onugem {
2265 for _, gem := range onu.GemPorts {
2266 if gem == gemPortID {
2267 return onu.OnuID, nil
2268 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002269 }
2270 }
Thomas Lee S94109f12020-03-03 16:39:29 +05302271 return uint32(0), olterrors.NewErrNotFound("onu-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002272 "serial-number": serialNumber,
2273 "interface-id": intfID,
2274 "gem-port-id": gemPortID},
Girish Kumarf26e4882020-03-05 06:49:10 +00002275 nil)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002276}
2277
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002278//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302279func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002280 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002281 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002282 var err error
2283
2284 if packetIn.IntfType == "pon" {
2285 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002286 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002287 // Called method is returning error with all data populated; just return the same
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002288 return logicalPortNum, err
2289 }
2290 if packetIn.PortNo != 0 {
2291 logicalPortNum = packetIn.PortNo
2292 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002293 uniID := uint32(0) // FIXME - multi-uni support
2294 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002295 }
2296 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302297 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002298 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002299 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002300 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002301 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2302 "logicalPortNum": logicalPortNum,
2303 "IntfType": packetIn.IntfType,
2304 "packet": hex.EncodeToString(packetIn.Pkt),
2305 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002306 return logicalPortNum, nil
2307}
2308
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002309//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302310func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002311 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002312 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302313
2314 f.lockCache.Lock()
2315 defer f.lockCache.Unlock()
2316 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2317
2318 gemPortID, ok := f.packetInGemPort[pktInkey]
2319 if ok {
2320 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2321 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002322 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302323 //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 +05302324 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302325 if err == nil {
2326 if gemPortID != 0 {
2327 f.packetInGemPort[pktInkey] = gemPortID
2328 log.Debugw("Found gem port from kv store and updating cache with gemport",
2329 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2330 return gemPortID, nil
2331 }
2332 }
Girish Kumarf26e4882020-03-05 06:49:10 +00002333 return uint32(0), olterrors.NewErrNotFound("gem-port", log.Fields{"pktinkey": pktInkey, "gem": gemPortID}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002334}
2335
npujarec5762e2020-01-01 14:08:48 +05302336func installFlowOnAllGemports(ctx context.Context,
2337 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002338 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
David K. Bainbridge794735f2020-02-11 21:01:37 -08002339 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32) error,
npujarec5762e2020-01-01 14:08:48 +05302340 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302341 classifier map[string]interface{}, action map[string]interface{},
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302342 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302343 ) error,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002344 args map[string]uint32,
2345 classifier map[string]interface{}, action map[string]interface{},
2346 logicalFlow *ofp.OfpFlowStats,
2347 gemPorts []uint32,
Girish Gowdrafae935c2020-02-17 19:21:44 +05302348 TpInst *tp.TechProfile,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002349 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002350 vlanID ...uint32) {
2351 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
Girish Gowdrafae935c2020-02-17 19:21:44 +05302352
2353 for _, gemPortAttribute := range TpInst.UpstreamGemPortAttributeList {
2354 var gemPortID uint32
2355 // The bit mapping for a gemport is expressed in tech-profile as a binary string. For example, 0b00000001
2356 // We need to trim prefix "0b", before further processing
2357 // Once the "0b" prefix is trimmed, we iterate each character in the string to identify which index
2358 // in the string is set to binary bit 1 (expressed as char '1' in the binary string).
2359 for pos, pbitSet := range strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix) {
2360 // If a particular character in the string is set to '1', identify the index of this character from
2361 // the LSB position which marks the PCP bit consumed by the given gem port.
2362 // This PCP bit now becomes a classifier in the flow.
2363 if pbitSet == BinaryBit1 {
2364 classifier[VlanPcp] = uint32(len(strings.TrimPrefix(gemPortAttribute.PbitMap, BinaryStringPrefix))) - 1 - uint32(pos)
2365 gemPortID = gemPortAttribute.GemportID
2366 if FlowType == HsiaFlow || FlowType == DhcpFlow || FlowType == IgmpFlow {
2367 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
2368 } else if FlowType == EapolFlow {
2369 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID, vlanID[0])
2370 } else {
2371 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2372 return
2373 }
2374 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04002375 }
2376 }
2377}
2378
David K. Bainbridge794735f2020-02-11 21:01:37 -08002379func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002380 log.Debug("Adding trap-dhcp-of-nni-flow")
2381 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002382 classifier[PacketTagType] = DoubleTag
2383 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002384 /* We manage flowId resource pool on per PON port basis.
2385 Since this situation is tricky, as a hack, we pass the NNI port
2386 index (network_intf_id) as PON port Index for the flowId resource
2387 pool. Also, there is no ONU Id available for trapping DHCP packets
2388 on NNI port, use onu_id as -1 (invalid)
2389 ****************** CAVEAT *******************
2390 This logic works if the NNI Port Id falls within the same valid
2391 range of PON Port Ids. If this doesn't work for some OLT Vendor
2392 we need to have a re-look at this.
2393 *********************************************
2394 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002395 onuID := -1
2396 uniID := -1
2397 gemPortID := -1
2398 allocID := -1
David K. Bainbridge794735f2020-02-11 21:01:37 -08002399 networkInterfaceID, err := getNniIntfID(classifier, action)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302400 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302401 return olterrors.NewErrNotFound("nni-intreface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002402 "classifier": classifier,
2403 "action": action},
Girish Kumarf26e4882020-03-05 06:49:10 +00002404 err)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302405 }
2406
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002407 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302408 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002409 log.Debug("Flow-exists-not-re-adding")
2410 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002411 }
npujarec5762e2020-01-01 14:08:48 +05302412 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002413 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302414 return olterrors.NewErrNotFound("dhcp-trap-nni-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002415 "interface-id": networkInterfaceID,
2416 "onu-id": onuID,
2417 "uni-id": uniID,
2418 "gem-port-id": gemPortID,
2419 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00002420 err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002421 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002422 classifierProto, err := makeOpenOltClassifierField(classifier)
2423 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002424 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002425 }
2426 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002427 actionProto, err := makeOpenOltActionField(action)
2428 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002429 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002430 }
2431 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002432 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2433 OnuId: int32(onuID), // OnuId not required
2434 UniId: int32(uniID), // UniId not used
2435 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002436 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002437 AllocId: int32(allocID), // AllocId not used
2438 NetworkIntfId: int32(networkInterfaceID),
2439 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002440 Classifier: classifierProto,
2441 Action: actionProto,
2442 Priority: int32(logicalFlow.Priority),
2443 Cookie: logicalFlow.Cookie,
2444 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002445 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002446 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002447 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002448 log.Debug("DHCP trap on NNI flow added to device successfully")
2449 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2450 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2451 int32(onuID),
2452 int32(uniID),
2453 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002454 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08002455 }
2456 return nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002457}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002458
Esin Karamanae41e2b2019-12-17 18:13:13 +00002459//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2460func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2461 var packetType string
2462 ovid, ivid := false, false
2463 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2464 vid := vlanID & VlanvIDMask
2465 if vid != ReservedVlan {
2466 ovid = true
2467 }
2468 }
2469 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2470 vid := uint32(metadata)
2471 if vid != ReservedVlan {
2472 ivid = true
2473 }
2474 }
2475 if ovid && ivid {
2476 packetType = DoubleTag
2477 } else if !ovid && !ivid {
2478 packetType = Untagged
2479 } else {
2480 packetType = SingleTag
2481 }
2482 return packetType
2483}
2484
2485//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
David K. Bainbridge794735f2020-02-11 21:01:37 -08002486func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) error {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002487 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2488 action := make(map[string]interface{})
2489 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2490 action[TrapToHost] = true
2491 /* We manage flowId resource pool on per PON port basis.
2492 Since this situation is tricky, as a hack, we pass the NNI port
2493 index (network_intf_id) as PON port Index for the flowId resource
2494 pool. Also, there is no ONU Id available for trapping packets
2495 on NNI port, use onu_id as -1 (invalid)
2496 ****************** CAVEAT *******************
2497 This logic works if the NNI Port Id falls within the same valid
2498 range of PON Port Ids. If this doesn't work for some OLT Vendor
2499 we need to have a re-look at this.
2500 *********************************************
2501 */
2502 onuID := -1
2503 uniID := -1
2504 gemPortID := -1
2505 allocID := -1
2506 networkInterfaceID, err := getNniIntfID(classifier, action)
2507 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302508 return olterrors.NewErrNotFound("nni-interface-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002509 "classifier": classifier,
2510 "action": action},
Girish Kumarf26e4882020-03-05 06:49:10 +00002511 err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002512 }
2513 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302514 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002515 log.Debug("igmp-flow-exists-not-re-adding")
2516 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002517 }
npujarec5762e2020-01-01 14:08:48 +05302518 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002519 if err != nil {
Thomas Lee S94109f12020-03-03 16:39:29 +05302520 return olterrors.NewErrNotFound("igmp-flow-id", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002521 "interface-id": networkInterfaceID,
2522 "onu-id": onuID,
2523 "uni-id": uniID,
2524 "gem-port-id": gemPortID,
2525 "cookie": flowStoreCookie},
Girish Kumarf26e4882020-03-05 06:49:10 +00002526 err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002527 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002528 classifierProto, err := makeOpenOltClassifierField(classifier)
2529 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002530 return olterrors.NewErrInvalidValue(log.Fields{"classifier": classifier}, err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002531 }
2532 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
David K. Bainbridge794735f2020-02-11 21:01:37 -08002533 actionProto, err := makeOpenOltActionField(action)
2534 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002535 return olterrors.NewErrInvalidValue(log.Fields{"action": action}, err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002536 }
2537 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2538 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2539 OnuId: int32(onuID), // OnuId not required
2540 UniId: int32(uniID), // UniId not used
2541 FlowId: flowID,
2542 FlowType: Downstream,
2543 AllocId: int32(allocID), // AllocId not used
2544 NetworkIntfId: int32(networkInterfaceID),
2545 GemportId: int32(gemPortID), // GemportId not used
2546 Classifier: classifierProto,
2547 Action: actionProto,
2548 Priority: int32(logicalFlow.Priority),
2549 Cookie: logicalFlow.Cookie,
2550 PortNo: portNo}
David K. Bainbridge794735f2020-02-11 21:01:37 -08002551 if err := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002552 return olterrors.NewErrFlowOp("add", flowID, log.Fields{"flow": downstreamflow}, err)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002553 }
David K. Bainbridge794735f2020-02-11 21:01:37 -08002554 log.Debug("IGMP Trap on NNI flow added to device successfully")
2555 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2556 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
2557 int32(onuID),
2558 int32(uniID),
2559 flowID, flowsToKVStore); err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002560 return olterrors.NewErrPersistence("update", "flow", flowID, log.Fields{"flow": downstreamflow}, err)
David K. Bainbridge794735f2020-02-11 21:01:37 -08002561 }
2562 return nil
Esin Karamanae41e2b2019-12-17 18:13:13 +00002563}
2564
salmansiddiqui7ac62132019-08-22 03:58:50 +00002565func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2566 if MeterID == 0 { // This should never happen
Thomas Lee S94109f12020-03-03 16:39:29 +05302567 return "", olterrors.NewErrInvalidValue(log.Fields{"meter-id": MeterID}, nil).Log()
salmansiddiqui7ac62132019-08-22 03:58:50 +00002568 }
2569 if Dir == tp_pb.Direction_UPSTREAM {
2570 return "upstream", nil
2571 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2572 return "downstream", nil
2573 }
2574 return "", nil
2575}
2576
npujarec5762e2020-01-01 14:08:48 +05302577func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002578 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2579 TpID uint32, uni string) {
2580 var gemPort uint32
2581 intfID := args[IntfID]
2582 onuID := args[OnuID]
2583 uniID := args[UniID]
2584 portNo := args[PortNo]
2585 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002586 if ipProto, ok := classifierInfo[IPProto]; ok {
2587 if ipProto.(uint32) == IPProtoDhcp {
2588 log.Info("Adding DHCP flow")
2589 if pcp, ok := classifierInfo[VlanPcp]; ok {
2590 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2591 tp_pb.Direction_UPSTREAM,
2592 pcp.(uint32))
2593 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302594 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002595 } else {
2596 //Adding DHCP upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302597 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002598 }
2599
2600 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002601 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2602 if pcp, ok := classifierInfo[VlanPcp]; ok {
2603 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2604 tp_pb.Direction_UPSTREAM,
2605 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302606 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002607 } else {
2608 //Adding IGMP upstream flow to all gem ports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302609 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002610 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002611 } else {
2612 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2613 return
2614 }
2615 } else if ethType, ok := classifierInfo[EthType]; ok {
2616 if ethType.(uint32) == EapEthType {
2617 log.Info("Adding EAPOL flow")
2618 var vlanID uint32
2619 if val, ok := classifierInfo[VlanVid]; ok {
2620 vlanID = (val.(uint32)) & VlanvIDMask
2621 } else {
2622 vlanID = DefaultMgmtVlan
2623 }
2624 if pcp, ok := classifierInfo[VlanPcp]; ok {
2625 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2626 tp_pb.Direction_UPSTREAM,
2627 pcp.(uint32))
2628
Girish Gowdrafae935c2020-02-17 19:21:44 +05302629 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002630 } else {
Girish Gowdrafae935c2020-02-17 19:21:44 +05302631 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002632 }
2633 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002634 } else if _, ok := actionInfo[PushVlan]; ok {
2635 log.Info("Adding upstream data rule")
2636 if pcp, ok := classifierInfo[VlanPcp]; ok {
2637 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2638 tp_pb.Direction_UPSTREAM,
2639 pcp.(uint32))
2640 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302641 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002642 } else {
2643 //Adding HSIA upstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302644 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002645 }
2646 } else if _, ok := actionInfo[PopVlan]; ok {
2647 log.Info("Adding Downstream data rule")
2648 if pcp, ok := classifierInfo[VlanPcp]; ok {
2649 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002650 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002651 pcp.(uint32))
2652 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302653 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002654 } else {
2655 //Adding HSIA downstream flow to all gemports
Girish Gowdrafae935c2020-02-17 19:21:44 +05302656 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, TpInst, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002657 }
2658 } else {
2659 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2660 return
2661 }
2662 // Send Techprofile download event to child device in go routine as it takes time
2663 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2664}
2665
Gamze Abakafee36392019-10-03 11:17:24 +00002666func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2667 flowIDList := f.flowsUsedByGemPort[gemPK]
2668 if len(flowIDList) > 1 {
2669 return true
2670 }
2671 return false
2672}
2673
npujarec5762e2020-01-01 14:08:48 +05302674func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2675 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002676 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2677 for _, currentGemPort := range currentGemPorts {
2678 for _, tpGemPort := range tpGemPorts {
2679 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2680 return true, currentGemPort
2681 }
2682 }
2683 }
Girish Gowdra54934262019-11-13 14:19:55 +05302684 if tpInst.InstanceCtrl.Onu == "single-instance" {
2685 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302686 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2687 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302688
2689 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2690 // still be used on other uni ports.
2691 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2692 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302693 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302694 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302695 for i := 0; i < len(tpInstances); i++ {
2696 tpI := tpInstances[i]
2697 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302698 for _, tpGemPort := range tpGemPorts {
2699 if tpGemPort.GemportID != gemPortID {
2700 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2701 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302702 }
2703 }
2704 }
2705 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302706 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002707 return false, 0
2708}
2709
salmansiddiqui7ac62132019-08-22 03:58:50 +00002710func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002711 for _, field := range flows.GetOfbFields(flow) {
2712 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002713 classifierInfo[EthType] = field.GetEthType()
2714 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002715 } else if field.Type == flows.ETH_DST {
2716 classifierInfo[EthDst] = field.GetEthDst()
2717 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002718 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002719 classifierInfo[IPProto] = field.GetIpProto()
2720 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002721 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002722 classifierInfo[InPort] = field.GetPort()
2723 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002724 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302725 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002726 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002727 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002728 classifierInfo[VlanPcp] = field.GetVlanPcp()
2729 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002730 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002731 classifierInfo[UDPDst] = field.GetUdpDst()
2732 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002733 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002734 classifierInfo[UDPSrc] = field.GetUdpSrc()
2735 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002736 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002737 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2738 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002739 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002740 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2741 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002742 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002743 classifierInfo[Metadata] = field.GetTableMetadata()
2744 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002745 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002746 classifierInfo[TunnelID] = field.GetTunnelId()
2747 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2748 } else {
2749 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2750 return
2751 }
2752 }
2753}
2754
2755func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002756 for _, action := range flows.GetActions(flow) {
2757 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002758 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002759 actionInfo[Output] = out.GetPort()
2760 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002761 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00002762 return olterrors.NewErrInvalidValue(log.Fields{"output-port": nil}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002763 }
Scott Baker355d1742019-10-24 10:57:52 -07002764 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002765 actionInfo[PopVlan] = true
2766 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002767 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002768 if out := action.GetPush(); out != nil {
2769 if tpid := out.GetEthertype(); tpid != 0x8100 {
2770 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2771 } else {
2772 actionInfo[PushVlan] = true
2773 actionInfo[TPID] = tpid
2774 log.Debugw("action-type-push-vlan",
2775 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2776 }
2777 }
Scott Baker355d1742019-10-24 10:57:52 -07002778 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002779 if out := action.GetSetField(); out != nil {
2780 if field := out.GetField(); field != nil {
2781 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
Girish Kumarf26e4882020-03-05 06:49:10 +00002782 return olterrors.NewErrInvalidValue(log.Fields{"openflow-class": ofClass}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002783 }
2784 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002785 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002786 }
2787 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002788 } else if action.Type == flows.GROUP {
2789 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002790 } else {
Girish Kumarf26e4882020-03-05 06:49:10 +00002791 return olterrors.NewErrInvalidValue(log.Fields{"action-type": action.Type}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002792 }
2793 }
2794 return nil
2795}
2796
Esin Karamanccb714b2019-11-29 15:02:06 +00002797func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2798 if ofbField := field.GetOfbField(); ofbField != nil {
2799 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2800 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2801 actionInfo[VlanVid] = vlan & 0xfff
2802 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2803 } else {
2804 log.Error("No Invalid vlan id in set vlan-vid action")
2805 }
2806 } else {
2807 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2808 }
2809 }
2810}
2811
2812func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2813 if action.GetGroup() == nil {
2814 log.Warn("No group entry found in the group action")
2815 } else {
2816 actionInfo[GroupID] = action.GetGroup().GroupId
2817 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2818 }
2819}
2820
salmansiddiqui7ac62132019-08-22 03:58:50 +00002821func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002822 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002823 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2824 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2825 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002826 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002827 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002828 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 +00002829 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302830 return olterrors.NewErrNotFound("child-in-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002831 "reason": "upstream pon-to-controller-flow, NO-inport-in-tunnelid",
Girish Kumarf26e4882020-03-05 06:49:10 +00002832 "flow": flow}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002833 }
2834 }
2835 } else {
2836 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2837 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002838 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002839 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002840 actionInfo[Output] = uniPort
2841 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 +00002842 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302843 return olterrors.NewErrNotFound("out-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002844 "reason": "downstream-nni-to-pon-port-flow, no-outport-in-tunnelid",
Girish Kumarf26e4882020-03-05 06:49:10 +00002845 "flow": flow}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002846 }
2847 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2848 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002849 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002850 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002851 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2852 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002853 } else {
Thomas Lee S94109f12020-03-03 16:39:29 +05302854 return olterrors.NewErrNotFound("nni-port", log.Fields{
David K. Bainbridge794735f2020-02-11 21:01:37 -08002855 "reason": "upstream-pon-to-nni-port-flow, no-inport-in-tunnelid",
2856 "in-port": classifierInfo[InPort].(uint32),
2857 "out-port": actionInfo[Output].(uint32),
Girish Kumarf26e4882020-03-05 06:49:10 +00002858 "flow": flow}, nil)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002859 }
2860 }
2861 }
2862 return nil
2863}
Gamze Abakafee36392019-10-03 11:17:24 +00002864
Chaitrashree G S90a17952019-11-14 21:51:21 -05002865func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002866 /* Metadata 8 bytes:
2867 Most Significant 2 Bytes = Inner VLAN
2868 Next 2 Bytes = Tech Profile ID(TPID)
2869 Least Significant 4 Bytes = Port ID
2870 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2871 subscriber related flows.
2872 */
2873 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2874 if metadata == 0 {
Girish Kumarf26e4882020-03-05 06:49:10 +00002875 return 0, olterrors.NewErrNotFound("metadata", log.Fields{"flow": flow}, nil)
Gamze Abakafee36392019-10-03 11:17:24 +00002876 }
2877 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002878 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002879}
2880
2881func appendUnique(slice []uint32, item uint32) []uint32 {
2882 for _, sliceElement := range slice {
2883 if sliceElement == item {
2884 return slice
2885 }
2886 }
2887 return append(slice, item)
2888}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302889
2890// getNniIntfID gets nni intf id from the flow classifier/action
2891func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2892
2893 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2894 if portType == voltha.Port_PON_OLT {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002895 intfID, err := IntfIDFromNniPortNum(action[Output].(uint32))
2896 if err != nil {
2897 log.Debugw("invalid-action-port-number",
2898 log.Fields{
2899 "port-number": action[Output].(uint32),
2900 "error": err})
2901 return uint32(0), err
2902 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302903 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2904 return intfID, nil
2905 } else if portType == voltha.Port_ETHERNET_NNI {
David K. Bainbridge794735f2020-02-11 21:01:37 -08002906 intfID, err := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2907 if err != nil {
2908 log.Debugw("invalid-classifier-port-number",
2909 log.Fields{
2910 "port-number": action[Output].(uint32),
2911 "error": err})
2912 return uint32(0), err
2913 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302914 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2915 return intfID, nil
2916 }
2917 return uint32(0), nil
2918}
2919
2920// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302921func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302922 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2923
2924 f.lockCache.Lock()
2925 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002926 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302927 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002928 if lookupGemPort == gemPort {
2929 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2930 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2931 return
2932 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302933 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002934 f.packetInGemPort[pktInkey] = gemPort
2935
npujarec5762e2020-01-01 14:08:48 +05302936 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002937 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 +05302938 return
2939}
2940
2941// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302942func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302943
2944 f.lockCache.Lock()
2945 defer f.lockCache.Unlock()
2946 onugem := f.onuGemInfo[intfID]
2947 for idx, onu := range onugem {
2948 if onu.OnuID == onuID {
2949 for _, uni := range onu.UniPorts {
2950 if uni == portNum {
2951 log.Debugw("uni already in cache, no need to update cache and kv store",
2952 log.Fields{"uni": portNum})
2953 return
2954 }
2955 }
2956 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2957 f.onuGemInfo[intfID] = onugem
2958 }
2959 }
npujarec5762e2020-01-01 14:08:48 +05302960 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302961}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302962
npujarec5762e2020-01-01 14:08:48 +05302963func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2964 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302965 if err != nil {
2966 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2967 return
2968 }
2969 for gem, FlowIDs := range flowIDsList {
2970 gemPK := gemPortKey{intf, uint32(gem)}
2971 f.flowsUsedByGemPort[gemPK] = FlowIDs
2972 }
2973 return
2974}
Esin Karamanccb714b2019-11-29 15:02:06 +00002975
2976//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2977//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302978func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2979 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002980 if err != nil {
2981 log.Error("Failed to get pon interface to multicast queue map")
2982 return
2983 }
2984 for intf, queueInfo := range storedMulticastQueueMap {
2985 q := queueInfoBrief{
2986 gemPortID: queueInfo[0],
2987 servicePriority: queueInfo[1],
2988 }
2989 f.interfaceToMcastQueueMap[intf] = &q
2990 }
2991}
2992
2993//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
2994//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
2995//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05302996func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
2997 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00002998 if err != nil {
Girish Kumarf26e4882020-03-05 06:49:10 +00002999 return nil, false, olterrors.NewErrNotFound("flow-group", log.Fields{"group-id": groupID}, err)
Esin Karamanccb714b2019-11-29 15:02:06 +00003000 }
3001 if exists {
3002 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
3003 }
3004 return nil, exists, nil
3005}
3006
3007func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
3008 groupDesc := ofp.OfpGroupDesc{
3009 Type: ofp.OfpGroupType_OFPGT_ALL,
3010 GroupId: groupID,
3011 }
3012 groupEntry := ofp.OfpGroupEntry{
3013 Desc: &groupDesc,
3014 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003015 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003016 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00003017 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00003018 bucket := ofp.OfpBucket{
3019 Actions: acts,
3020 }
3021 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00003022 }
Esin Karamanccb714b2019-11-29 15:02:06 +00003023 return &groupEntry
3024}