blob: 892663f51f977e5fcd981157f45af2b0f570938a [file] [log] [blame]
manikkaraj kbf256be2019-03-25 00:13:48 +05301/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070017//Package adaptercore provides the utility for olt devices, flows and statistics
manikkaraj kbf256be2019-03-25 00:13:48 +053018package adaptercore
19
20import (
21 "context"
22 "crypto/md5"
Matteo Scandolo6056e822019-11-13 14:05:29 -080023 "encoding/hex"
manikkaraj kbf256be2019-03-25 00:13:48 +053024 "encoding/json"
25 "errors"
26 "fmt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040027 "math/big"
William Kurkian740a09c2019-10-23 17:07:38 -040028 "sync"
Girish Gowdra3d633032019-12-10 16:37:05 +053029 "time"
Manikkaraj kb1d51442019-07-23 10:41:02 -040030
Esin Karamanccb714b2019-11-29 15:02:06 +000031 "github.com/opencord/voltha-lib-go/v3/pkg/flows"
32 "github.com/opencord/voltha-lib-go/v3/pkg/log"
33 tp "github.com/opencord/voltha-lib-go/v3/pkg/techprofile"
Manikkaraj k884c1242019-04-11 16:26:42 +053034 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
Esin Karamanccb714b2019-11-29 15:02:06 +000035 "github.com/opencord/voltha-protos/v3/go/common"
36 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
37 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
38 openoltpb2 "github.com/opencord/voltha-protos/v3/go/openolt"
39 tp_pb "github.com/opencord/voltha-protos/v3/go/tech_profile"
40 "github.com/opencord/voltha-protos/v3/go/voltha"
Chaitrashree G S579fe732019-08-20 20:50:47 -040041
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040042 //deepcopy "github.com/getlantern/deepcopy"
Girish Gowdra3d633032019-12-10 16:37:05 +053043 "github.com/EagleChen/mapmutex"
Daniele Rossi22db98e2019-07-11 11:50:00 +000044 "google.golang.org/grpc/codes"
45 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053046)
47
48const (
49 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053050
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070051 //HsiaFlow flow category
52 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053053
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070054 //EapolFlow flow category
55 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053056
Manikkaraj kb1d51442019-07-23 10:41:02 -040057 //DhcpFlow flow category
58 DhcpFlow = "DHCP_FLOW"
59
Esin Karamanccb714b2019-11-29 15:02:06 +000060 //MulticastFlow flow category
61 MulticastFlow = "MULTICAST_FLOW"
62
Esin Karamanae41e2b2019-12-17 18:13:13 +000063 //IgmpFlow flow category
64 IgmpFlow = "IGMP_FLOW"
65
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070066 //IPProtoDhcp flow category
67 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053068
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070069 //IPProtoIgmp flow category
70 IPProtoIgmp = 2
71
72 //EapEthType eapethtype value
73 EapEthType = 0x888e
74 //LldpEthType lldp ethtype value
75 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000076 //IPv4EthType IPv4 ethernet type value
77 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070078
79 //IgmpProto proto value
80 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053081
82 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070083
Humera Kouser94d7a842019-08-25 19:04:32 -040084 //ReservedVlan Transparent Vlan
David K. Bainbridge82efc492019-09-04 09:57:11 -070085 ReservedVlan = 4095
Harsh Awasthiea45af72019-08-26 02:39:00 -040086
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070087 //DefaultMgmtVlan default vlan value
88 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053089
manikkaraj kbf256be2019-03-25 00:13:48 +053090 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070091
David K. Bainbridge82efc492019-09-04 09:57:11 -070092 //Upstream constant
93 Upstream = "upstream"
94 //Downstream constant
95 Downstream = "downstream"
Esin Karamanccb714b2019-11-29 15:02:06 +000096 //Multicast constant
97 Multicast = "multicast"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070098 //PacketTagType constant
99 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700100 //Untagged constant
101 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700102 //SingleTag constant
103 SingleTag = "single_tag"
104 //DoubleTag constant
105 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530106
107 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700108
109 //EthType constant
110 EthType = "eth_type"
Esin Karamanccb714b2019-11-29 15:02:06 +0000111 //EthDst constant
112 EthDst = "eth_dst"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700113 //TPID constant
114 TPID = "tpid"
115 //IPProto constant
116 IPProto = "ip_proto"
117 //InPort constant
118 InPort = "in_port"
119 //VlanVid constant
120 VlanVid = "vlan_vid"
121 //VlanPcp constant
122 VlanPcp = "vlan_pcp"
123
124 //UDPDst constant
125 UDPDst = "udp_dst"
126 //UDPSrc constant
127 UDPSrc = "udp_src"
128 //Ipv4Dst constant
129 Ipv4Dst = "ipv4_dst"
130 //Ipv4Src constant
131 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700132 //Metadata constant
133 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700134 //TunnelID constant
135 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700136 //Output constant
137 Output = "output"
Esin Karamanccb714b2019-11-29 15:02:06 +0000138 //GroupID constant
139 GroupID = "group_id"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700140 // Actions
141
142 //PopVlan constant
143 PopVlan = "pop_vlan"
144 //PushVlan constant
145 PushVlan = "push_vlan"
146 //TrapToHost constant
147 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400148 //MaxMeterBand constant
149 MaxMeterBand = 2
150 //VlanPCPMask contant
151 VlanPCPMask = 0xFF
152 //VlanvIDMask constant
153 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000154 //IntfID constant
155 IntfID = "intfId"
156 //OnuID constant
157 OnuID = "onuId"
158 //UniID constant
159 UniID = "uniId"
160 //PortNo constant
161 PortNo = "portNo"
162 //AllocID constant
163 AllocID = "allocId"
Esin Karamanccb714b2019-11-29 15:02:06 +0000164
165 //NoneOnuID constant
166 NoneOnuID = -1
167 //NoneUniID constant
168 NoneUniID = -1
169 //NoneGemPortID constant
170 NoneGemPortID = -1
manikkaraj kbf256be2019-03-25 00:13:48 +0530171)
172
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400173type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700174 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400175 gemPort uint32
176}
177
Girish Gowdra3d633032019-12-10 16:37:05 +0530178type pendingFlowDeleteKey struct {
179 intfID uint32
180 onuID uint32
181 uniID uint32
182}
183
184type tpLockKey struct {
185 intfID uint32
186 onuID uint32
187 uniID uint32
188}
189
Gamze Abakafee36392019-10-03 11:17:24 +0000190type schedQueue struct {
191 direction tp_pb.Direction
192 intfID uint32
193 onuID uint32
194 uniID uint32
195 tpID uint32
196 uniPort uint32
197 tpInst *tp.TechProfile
198 meterID uint32
199 flowMetadata *voltha.FlowMetadata
200}
201
Esin Karamanccb714b2019-11-29 15:02:06 +0000202type queueInfoBrief struct {
203 gemPortID uint32
204 servicePriority uint32
205}
206
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700207//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530208type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000209 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000210 deviceHandler *DeviceHandler
211 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000212 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530213 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
214 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
215 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
216 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530217 pendingFlowDelete sync.Map
218 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
Esin Karamanccb714b2019-11-29 15:02:06 +0000219 perUserFlowHandleLock *mapmutex.Mutex
220 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 +0530221}
222
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700223//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
npujarec5762e2020-01-01 14:08:48 +0530224func NewFlowManager(ctx context.Context, dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530225 log.Info("Initializing flow manager")
226 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530227 var err error
228 var idx uint32
229
manikkaraj kbf256be2019-03-25 00:13:48 +0530230 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530231 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000232 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530233 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530234 log.Error("Error while populating tech profile mgr\n")
235 return nil
236 }
William Kurkian740a09c2019-10-23 17:07:38 -0400237 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530238 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
239 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
240 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
241 ponPorts := rMgr.DevInfo.GetPonPorts()
242 //Load the onugem info cache from kv store on flowmanager start
243 for idx = 0; idx < ponPorts; idx++ {
npujarec5762e2020-01-01 14:08:48 +0530244 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(ctx, idx); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530245 log.Error("Failed to load onu gem info cache")
246 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530247 //Load flowID list per gem map per interface from the kvstore.
npujarec5762e2020-01-01 14:08:48 +0530248 flowMgr.loadFlowIDlistForGem(ctx, idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530249 }
250 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530251 flowMgr.pendingFlowDelete = sync.Map{}
252 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
Esin Karamanccb714b2019-11-29 15:02:06 +0000253 flowMgr.interfaceToMcastQueueMap = make(map[uint32]*queueInfoBrief)
254 //load interface to multicast queue map from kv store
npujarec5762e2020-01-01 14:08:48 +0530255 flowMgr.loadInterfaceToMulticastQueueMap(ctx)
manikkaraj kbf256be2019-03-25 00:13:48 +0530256 log.Info("Initialization of flow manager success!!")
257 return &flowMgr
258}
259
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700260func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700261 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400262 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700263 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700264 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400265 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700266 return uint64(flowID), nil
Esin Karamanccb714b2019-11-29 15:02:06 +0000267 } else if direction == Multicast {
268 log.Debug("multicast flow, shifting id")
269 return 0x2<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400270 } else {
271 log.Debug("Unrecognized direction")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700272 return 0, fmt.Errorf("unrecognized direction %s", direction)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400273 }
274}
275
npujarec5762e2020-01-01 14:08:48 +0530276func (f *OpenOltFlowMgr) registerFlow(ctx context.Context, flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400277 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700278 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000279 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
280 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
281 if !ok {
282 flowIDList = []uint32{deviceFlow.FlowId}
283 }
284 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
285 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530286 // update the flowids for a gem to the KVstore
npujarec5762e2020-01-01 14:08:48 +0530287 f.resourceMgr.UpdateFlowIDsForGem(ctx, uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400288}
289
npujarec5762e2020-01-01 14:08:48 +0530290func (f *OpenOltFlowMgr) divideAndAddFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000291 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
292 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000293 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530294 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400295 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530296
Manikkaraj kb1d51442019-07-23 10:41:02 -0400297 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000298 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400299 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
300 // is because the flow is an NNI flow and there would be no onu resources associated with it
301 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400302 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400303 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530304 return
305 }
306
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530307 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400308 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530309
310 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
311 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
npujarec5762e2020-01-01 14:08:48 +0530312 allocID, gemPorts, TpInst = f.createTcontGemports(ctx, intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +0530313 if allocID == 0 || gemPorts == nil || TpInst == nil {
314 log.Error("alloc-id-gem-ports-tp-unavailable")
315 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
316 return
317 }
318 args := make(map[string]uint32)
319 args[IntfID] = intfID
320 args[OnuID] = onuID
321 args[UniID] = uniID
322 args[PortNo] = portNo
323 args[AllocID] = allocID
324
325 /* Flows can be added specific to gemport if p-bits are received.
326 * If no pbit mentioned then adding flows for all gemports
327 */
npujarec5762e2020-01-01 14:08:48 +0530328 f.checkAndAddFlow(ctx, args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
Girish Gowdra3d633032019-12-10 16:37:05 +0530329 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
330 } else {
331 log.Errorw("failed to acquire per user flow handle lock",
332 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400333 return
334 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530335}
336
salmansiddiqui7ac62132019-08-22 03:58:50 +0000337// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530338func (f *OpenOltFlowMgr) CreateSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400339
Gamze Abakafee36392019-10-03 11:17:24 +0000340 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
341 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
342 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400343
Gamze Abakafee36392019-10-03 11:17:24 +0000344 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000345 if err != nil {
346 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400347 }
348
349 /* Lets make a simple assumption that if the meter-id is present on the KV store,
350 * then the scheduler and queues configuration is applied on the OLT device
351 * in the given direction.
352 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000353
Manikkaraj kb1d51442019-07-23 10:41:02 -0400354 var SchedCfg *tp_pb.SchedulerConfig
npujarec5762e2020-01-01 14:08:48 +0530355 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400356 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000357 log.Error("Failed to get meter for intf %d, onuid %d, uniid %d", sq.intfID, sq.onuID, sq.uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400358 return err
359 }
360 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000361 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400362 log.Debug("Scheduler already created for upstream")
363 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400364 }
Gamze Abakafee36392019-10-03 11:17:24 +0000365 log.Errorw("Dynamic meter update not supported", log.Fields{"KvStoreMeterId": KvStoreMeter.MeterId, "MeterID-in-flow": sq.meterID})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000366 return errors.New("invalid-meter-id-in-flow")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400367 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000368
Gamze Abakafee36392019-10-03 11:17:24 +0000369 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000370
Gamze Abakafee36392019-10-03 11:17:24 +0000371 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000372 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000373 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000374 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400375 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000376
377 if err != nil {
378 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
379 return err
380 }
381
Manikkaraj kb1d51442019-07-23 10:41:02 -0400382 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000383 if sq.flowMetadata != nil {
384 for _, meter := range sq.flowMetadata.Meters {
385 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400386 meterConfig = meter
387 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
388 break
389 }
390 }
391 } else {
392 log.Error("Flow-metadata-is-not-present-in-flow")
393 }
394 if meterConfig == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000395 log.Errorw("Could-not-get-meterbands-from-flowMetadata", log.Fields{"flowMetadata": sq.flowMetadata,
396 "MeterID": sq.meterID})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000397 return errors.New("failed-to-get-meter-from-flowMetadata")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400398 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000399 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000400 return errors.New("invalid-number-of-bands-in-meter")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400401 }
402 cir := meterConfig.Bands[0].Rate
403 cbs := meterConfig.Bands[0].BurstSize
404 eir := meterConfig.Bands[1].Rate
405 ebs := meterConfig.Bands[1].BurstSize
406 pir := cir + eir
407 pbs := cbs + ebs
408 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
409
Gamze Abakafee36392019-10-03 11:17:24 +0000410 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400411
npujarec5762e2020-01-01 14:08:48 +0530412 if err := f.pushSchedulerQueuesToDevice(ctx, sq, TrafficShaping, TrafficSched); err != nil {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000413 log.Errorw("Failed to push traffic scheduler and queues to device", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400414 return err
415 }
416
salmansiddiqui7ac62132019-08-22 03:58:50 +0000417 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400418 * store the meter id on the KV store, for further reference.
419 */
npujarec5762e2020-01-01 14:08:48 +0530420 if err := f.resourceMgr.UpdateMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID, meterConfig); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000421 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400422 return err
423 }
424 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
425 "Meter": meterConfig})
426 return nil
427}
428
npujarec5762e2020-01-01 14:08:48 +0530429func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(ctx context.Context, sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000430
431 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
432
433 if err != nil {
434 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
435 return err
436 }
437
438 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
npujarec5762e2020-01-01 14:08:48 +0530439 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Girish Kumar8f73fe02019-12-09 13:19:37 +0000440 IntfId: sq.intfID, OnuId: sq.onuID,
441 UniId: sq.uniID, PortNo: sq.uniPort,
442 TrafficScheds: TrafficSched}); err != nil {
443 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
444 return err
445 }
446
447 // On receiving the CreateTrafficQueues request, the driver should create corresponding
448 // downstream queues.
449 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
npujarec5762e2020-01-01 14:08:48 +0530450 if _, err := f.deviceHandler.Client.CreateTrafficQueues(ctx,
Girish Kumar8f73fe02019-12-09 13:19:37 +0000451 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
452 UniId: sq.uniID, PortNo: sq.uniPort,
453 TrafficQueues: trafficQueues}); err != nil {
454 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
455 return err
456 }
457
Esin Karamanccb714b2019-11-29 15:02:06 +0000458 if sq.direction == tp_pb.Direction_DOWNSTREAM {
459 multicastTrafficQueues := f.techprofile[sq.intfID].GetMulticastTrafficQueues(sq.tpInst)
460 if len(multicastTrafficQueues) > 0 {
461 if _, present := f.interfaceToMcastQueueMap[sq.intfID]; !present {
462 //assumed that there is only one queue per PON for the multicast service
463 //the default queue with multicastQueuePerPonPort.Priority per a pon interface is used for multicast service
464 //just put it in interfaceToMcastQueueMap to use for building group members
465 multicastQueuePerPonPort := multicastTrafficQueues[0]
466 f.interfaceToMcastQueueMap[sq.intfID] = &queueInfoBrief{
467 gemPortID: multicastQueuePerPonPort.GemportId,
468 servicePriority: multicastQueuePerPonPort.Priority,
469 }
470 //also store the queue info in kv store
npujarec5762e2020-01-01 14:08:48 +0530471 f.resourceMgr.AddMcastQueueForIntf(ctx, sq.intfID,
Esin Karamanccb714b2019-11-29 15:02:06 +0000472 multicastQueuePerPonPort.GemportId,
473 multicastQueuePerPonPort.Priority)
474 }
475 }
476 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000477 return nil
478}
479
salmansiddiqui7ac62132019-08-22 03:58:50 +0000480// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
npujarec5762e2020-01-01 14:08:48 +0530481func (f *OpenOltFlowMgr) RemoveSchedulerQueues(ctx context.Context, sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400482
483 var Direction string
484 var SchedCfg *tp_pb.SchedulerConfig
485 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000486 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
487 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
488 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000489 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400490 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000491 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000492 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400493 Direction = "downstream"
494 }
495
Girish Kumar8f73fe02019-12-09 13:19:37 +0000496 if err != nil {
497 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
498 return err
499 }
500
npujarec5762e2020-01-01 14:08:48 +0530501 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400502 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000503 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400504 return err
505 }
506 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000507 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 -0400508 return nil
509 }
510 cir := KVStoreMeter.Bands[0].Rate
511 cbs := KVStoreMeter.Bands[0].BurstSize
512 eir := KVStoreMeter.Bands[1].Rate
513 ebs := KVStoreMeter.Bands[1].BurstSize
514 pir := cir + eir
515 pbs := cbs + ebs
516
517 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
518
Gamze Abakafee36392019-10-03 11:17:24 +0000519 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000520
521 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
522 if err != nil {
523 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
524 return err
525 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400526
npujarec5762e2020-01-01 14:08:48 +0530527 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(ctx,
Gamze Abakafee36392019-10-03 11:17:24 +0000528 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
529 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400530 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000531 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400532 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400533 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000534 log.Debug("Removed traffic queues successfully")
npujarec5762e2020-01-01 14:08:48 +0530535 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(ctx, &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000536 IntfId: sq.intfID, OnuId: sq.onuID,
537 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400538 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000539 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400540 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400541 }
542
salmansiddiqui7ac62132019-08-22 03:58:50 +0000543 log.Debug("Removed traffic schedulers successfully")
544
545 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400546 * delete the meter id on the KV store.
547 */
npujarec5762e2020-01-01 14:08:48 +0530548 err = f.resourceMgr.RemoveMeterIDForOnu(ctx, Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400549 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000550 log.Errorf("Failed to remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000551 return 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()) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530655 log.Errorw("Error while populating techprofile",
Manikkaraj kb1d51442019-07-23 10:41:02 -0400656 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000657 return errors.New("error while populating techprofile mgrs")
manikkaraj kbf256be2019-03-25 00:13:48 +0530658 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400659 log.Infow("Populated techprofile for ponports successfully",
660 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530661 return nil
662}
663
npujarec5762e2020-01-01 14:08:48 +0530664func (f *OpenOltFlowMgr) addUpstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530665 portNo uint32, uplinkClassifier map[string]interface{},
666 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700667 allocID uint32, gemportID uint32) {
668 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530669 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
npujarec5762e2020-01-01 14:08:48 +0530670 f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700671 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530672 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530673}
674
npujarec5762e2020-01-01 14:08:48 +0530675func (f *OpenOltFlowMgr) addDownstreamDataFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530676 portNo uint32, downlinkClassifier map[string]interface{},
677 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700678 allocID uint32, gemportID uint32) {
679 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530680 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
681 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400682 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
683 if vlan, exists := downlinkClassifier[VlanVid]; exists {
684 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700685 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400686 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
687 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
688 return
689 }
690 }
691 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530692 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400693
Manikkaraj k884c1242019-04-11 16:26:42 +0530694 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700695 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400696 // vlan_vid is a uint32. must be type asserted as such or conversion fails
697 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530698 if ok {
699 downlinkAction[VlanVid] = dlClVid & 0xfff
700 } else {
701 log.Error("dl-classifier-vid-type-conversion-failed")
702 return
703 }
704
npujarec5762e2020-01-01 14:08:48 +0530705 f.addHSIAFlow(ctx, intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700706 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530707}
708
npujarec5762e2020-01-01 14:08:48 +0530709func (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 +0530710 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700711 allocID uint32, gemPortID uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530712 var networkIntfID uint32
Manikkaraj k884c1242019-04-11 16:26:42 +0530713 /* One of the OLT platform (Broadcom BAL) requires that symmetric
714 flows require the same flow_id to be used across UL and DL.
715 Since HSIA flow is the only symmetric flow currently, we need to
716 re-use the flow_id across both direction. The 'flow_category'
717 takes priority over flow_cookie to find any available HSIA_FLOW
718 id for the ONU.
719 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700720 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
721 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530722 "logicalFlow": *logicalFlow})
Gamze Abakafee36392019-10-03 11:17:24 +0000723 var vlanPbit uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400724 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000725 vlanPbit = classifier[VlanPcp].(uint32)
726 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400727 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700728 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530729 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530730 log.Debug("Flow-exists--not-re-adding")
731 return
732 }
npujarec5762e2020-01-01 14:08:48 +0530733 flowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530734 if err != nil {
735 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
736 return
737 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700738 var classifierProto *openoltpb2.Classifier
739 var actionProto *openoltpb2.Action
Manikkaraj k884c1242019-04-11 16:26:42 +0530740 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
741 log.Error("Error in making classifier protobuf for hsia flow")
742 return
743 }
744 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
745 if actionProto = makeOpenOltActionField(action); actionProto == nil {
746 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
747 return
748 }
749 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530750 networkIntfID, err = getNniIntfID(classifier, action)
751 if err != nil {
752 log.Error("Failed to get nniIntf ID")
753 return
754 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700755 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
756 OnuId: int32(onuID),
757 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000758 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530759 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700760 AllocId: int32(allocID),
761 NetworkIntfId: int32(networkIntfID),
762 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530763 Classifier: classifierProto,
764 Action: actionProto,
765 Priority: int32(logicalFlow.Priority),
766 Cookie: logicalFlow.Cookie,
767 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +0530768 if ok := f.addFlowToDevice(ctx, logicalFlow, &flow); ok {
Manikkaraj k884c1242019-04-11 16:26:42 +0530769 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
npujarec5762e2020-01-01 14:08:48 +0530770 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
771 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
Manikkaraj k884c1242019-04-11 16:26:42 +0530772 flow.OnuId,
773 flow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400774 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530775 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
776 return
777 }
778 }
779}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000780
npujarec5762e2020-01-01 14:08:48 +0530781func (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) {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530782
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700783 var dhcpFlow openoltpb2.Flow
784 var actionProto *openoltpb2.Action
785 var classifierProto *openoltpb2.Classifier
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530786 var flowID uint32
787 networkIntfID, err := getNniIntfID(classifier, action)
788 if err != nil {
789 log.Error("Failed to get nniIntf ID")
790 return
791 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530792
793 // Clear the action map
794 for k := range action {
795 delete(action, k)
796 }
797
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700798 action[TrapToHost] = true
799 classifier[UDPSrc] = uint32(68)
800 classifier[UDPDst] = uint32(67)
801 classifier[PacketTagType] = SingleTag
802 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530803
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700804 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530805 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530806 log.Debug("Flow-exists--not-re-adding")
807 return
808 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530809
npujarec5762e2020-01-01 14:08:48 +0530810 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 +0530811
812 if err != nil {
Girish Gowdra3d633032019-12-10 16:37:05 +0530813 log.Errorw("flowId unavailable for UL DHCP", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530814 return
815 }
816
817 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
818
819 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
820 log.Error("Error in making classifier protobuf for ul flow")
821 return
822 }
823 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
824 if actionProto = makeOpenOltActionField(action); actionProto == nil {
825 log.Error("Error in making action protobuf for ul flow")
826 return
827 }
828
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700829 dhcpFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
830 OnuId: int32(onuID),
831 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530832 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700833 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700834 AllocId: int32(allocID),
835 NetworkIntfId: int32(networkIntfID),
836 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530837 Classifier: classifierProto,
838 Action: actionProto,
839 Priority: int32(logicalFlow.Priority),
840 Cookie: logicalFlow.Cookie,
841 PortNo: portNo}
842
npujarec5762e2020-01-01 14:08:48 +0530843 if ok := f.addFlowToDevice(ctx, logicalFlow, &dhcpFlow); ok {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530844 log.Debug("DHCP UL flow added to device successfully")
npujarec5762e2020-01-01 14:08:48 +0530845 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
846 if err := f.updateFlowInfoToKVStore(ctx, dhcpFlow.AccessIntfId,
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530847 dhcpFlow.OnuId,
848 dhcpFlow.UniId,
849 dhcpFlow.FlowId, flowsToKVStore); err != nil {
850 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
851 return
852 }
853 }
854
manikkaraj kbf256be2019-03-25 00:13:48 +0530855 return
856}
857
Esin Karamanae41e2b2019-12-17 18:13:13 +0000858//addIGMPTrapFlow creates IGMP trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530859func (f *OpenOltFlowMgr) addIGMPTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Esin Karamanae41e2b2019-12-17 18:13:13 +0000860 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) {
npujarec5762e2020-01-01 14:08:48 +0530861 f.addUpstreamTrapFlow(ctx, intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +0000862}
863
864//addUpstreamTrapFlow creates a trap-to-host flow
npujarec5762e2020-01-01 14:08:48 +0530865func (f *OpenOltFlowMgr) addUpstreamTrapFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Esin Karamanae41e2b2019-12-17 18:13:13 +0000866 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) {
867
868 var flow openoltpb2.Flow
869 var actionProto *openoltpb2.Action
870 var classifierProto *openoltpb2.Classifier
871
872 networkIntfID, err := getNniIntfID(classifier, action)
873 if err != nil {
874 log.Error("Failed to get nniIntf ID")
875 return
876 }
877
878 // Clear the action map
879 for k := range action {
880 delete(action, k)
881 }
882
883 action[TrapToHost] = true
884 classifier[PacketTagType] = SingleTag
885 delete(classifier, VlanVid)
886
887 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530888 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000889 log.Debug("Flow-exists--not-re-adding")
890 return
891 }
892
npujarec5762e2020-01-01 14:08:48 +0530893 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 +0000894
895 if err != nil {
896 log.Errorw("flowId unavailable for upstream trap flow", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie, "flowType": flowType})
897 return
898 }
899
900 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
901
902 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
903 log.Error("Error in making classifier protobuf for ul flow")
904 return
905 }
906 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
907 if actionProto = makeOpenOltActionField(action); actionProto == nil {
908 log.Error("Error in making action protobuf for ul flow")
909 return
910 }
911
912 flow = openoltpb2.Flow{AccessIntfId: int32(intfID),
913 OnuId: int32(onuID),
914 UniId: int32(uniID),
915 FlowId: flowID,
916 FlowType: Upstream,
917 AllocId: int32(allocID),
918 NetworkIntfId: int32(networkIntfID),
919 GemportId: int32(gemPortID),
920 Classifier: classifierProto,
921 Action: actionProto,
922 Priority: int32(logicalFlow.Priority),
923 Cookie: logicalFlow.Cookie,
924 PortNo: portNo}
925
npujarec5762e2020-01-01 14:08:48 +0530926 if ok := f.addFlowToDevice(ctx, logicalFlow, &flow); ok {
Esin Karamanae41e2b2019-12-17 18:13:13 +0000927 log.Debugf("%s UL flow added to device successfully", flowType)
928
npujarec5762e2020-01-01 14:08:48 +0530929 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
930 if err := f.updateFlowInfoToKVStore(ctx, flow.AccessIntfId,
Esin Karamanae41e2b2019-12-17 18:13:13 +0000931 flow.OnuId,
932 flow.UniId,
933 flow.FlowId, flowsToKVStore); err != nil {
934 log.Errorw("Error uploading UL flow into KV store", log.Fields{"flow": flow, "error": err})
935 return
936 }
937 }
938
939 return
940}
941
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700942// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
npujarec5762e2020-01-01 14:08:48 +0530943func (f *OpenOltFlowMgr) addEAPOLFlow(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, vlanID uint32, classifier map[string]interface{}, action map[string]interface{}) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700944 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 +0530945
946 uplinkClassifier := make(map[string]interface{})
947 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530948
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700949 var upstreamFlow openoltpb2.Flow
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530950 var networkIntfID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530951
952 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700953 uplinkClassifier[EthType] = uint32(EapEthType)
954 uplinkClassifier[PacketTagType] = SingleTag
955 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530956 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700957 uplinkAction[TrapToHost] = true
958 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
npujarec5762e2020-01-01 14:08:48 +0530959 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
Girish Gowdra3d633032019-12-10 16:37:05 +0530960 log.Debug("Flow-exists--not-re-adding")
961 return
962 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530963 //Add Uplink EAPOL Flow
npujarec5762e2020-01-01 14:08:48 +0530964 uplinkFlowID, err := f.resourceMgr.GetFlowID(ctx, intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530965 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700966 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manikkaraj k884c1242019-04-11 16:26:42 +0530967 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530968 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700969 var classifierProto *openoltpb2.Classifier
970 var actionProto *openoltpb2.Action
971 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530972
973 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
974 log.Error("Error in making classifier protobuf for ul flow")
975 return
976 }
977 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
978 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
979 log.Error("Error in making action protobuf for ul flow")
980 return
981 }
982 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530983 networkIntfID, err = getNniIntfID(classifier, action)
984 if err != nil {
985 log.Error("Failed to get nniIntf ID")
986 return
987 }
988
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700989 upstreamFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
990 OnuId: int32(onuID),
991 UniId: int32(uniID),
992 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700993 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700994 AllocId: int32(allocID),
995 NetworkIntfId: int32(networkIntfID),
996 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +0530997 Classifier: classifierProto,
998 Action: actionProto,
999 Priority: int32(logicalFlow.Priority),
1000 Cookie: logicalFlow.Cookie,
1001 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +05301002 if ok := f.addFlowToDevice(ctx, logicalFlow, &upstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +05301003 log.Debug("EAPOL UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001004 flowCategory := "EAPOL"
npujarec5762e2020-01-01 14:08:48 +05301005 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
1006 if err := f.updateFlowInfoToKVStore(ctx, upstreamFlow.AccessIntfId,
manikkaraj kbf256be2019-03-25 00:13:48 +05301007 upstreamFlow.OnuId,
1008 upstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001009 upstreamFlow.FlowId,
1010 /* lowCategory, */
1011 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +05301012 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
1013 return
1014 }
1015 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301016
manikkaraj kbf256be2019-03-25 00:13:48 +05301017 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
1018}
1019
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001020func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openoltpb2.Classifier {
1021 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -07001022
1023 classifier.EthType, _ = classifierInfo[EthType].(uint32)
1024 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
1025 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
1026 vid := vlanID & VlanvIDMask
1027 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001028 classifier.OVid = vid
1029 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301030 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001031 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1032 vid := uint32(metadata)
1033 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -04001034 classifier.IVid = vid
1035 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301036 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001037 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001038 if vlanPcp == 0 {
1039 classifier.OPbits = VlanPCPMask
1040 } else {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001041 classifier.OPbits = vlanPcp & VlanPCPMask
Manikkaraj kb1d51442019-07-23 10:41:02 -04001042 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301043 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001044 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
1045 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
1046 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1047 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
Esin Karamanccb714b2019-11-29 15:02:06 +00001048 classifier.DstMac, _ = classifierInfo[EthDst].([]uint8)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001049 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1050 classifier.PktTagType = pktTagType
1051
1052 switch pktTagType {
1053 case SingleTag:
1054 case DoubleTag:
1055 case Untagged:
1056 default:
manikkaraj kbf256be2019-03-25 00:13:48 +05301057 log.Error("Invalid tag type in classifier") // should not hit
1058 return nil
1059 }
1060 }
1061 return &classifier
1062}
1063
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001064func makeOpenOltActionField(actionInfo map[string]interface{}) *openoltpb2.Action {
1065 var actionCmd openoltpb2.ActionCmd
1066 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301067 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001068 if _, ok := actionInfo[PopVlan]; ok {
1069 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301070 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001071 } else if _, ok := actionInfo[PushVlan]; ok {
1072 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301073 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001074 } else if _, ok := actionInfo[TrapToHost]; ok {
1075 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301076 } else {
1077 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
1078 return nil
1079 }
1080 return &action
1081}
1082
Manikkaraj kb1d51442019-07-23 10:41:02 -04001083func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1084 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301085}
1086
Gamze Abakafee36392019-10-03 11:17:24 +00001087// DeleteTechProfileInstances removes the tech profile instances from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301088func (f *OpenOltFlowMgr) DeleteTechProfileInstances(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, sn string) error {
1089 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(ctx, intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001090 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001091 for _, tpID := range tpIDList {
npujarec5762e2020-01-01 14:08:48 +05301092 if err := f.DeleteTechProfileInstance(ctx, intfID, onuID, uniID, uniPortName, tpID); err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +00001093 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
Girish Gowdra54934262019-11-13 14:19:55 +05301094 // return err
1095 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001096 }
1097 }
1098 return nil
1099}
1100
1101// DeleteTechProfileInstance removes the tech profile instance from persistent storage
npujarec5762e2020-01-01 14:08:48 +05301102func (f *OpenOltFlowMgr) DeleteTechProfileInstance(ctx context.Context, intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
Gamze Abakafee36392019-10-03 11:17:24 +00001103 if uniPortName == "" {
1104 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1105 }
npujarec5762e2020-01-01 14:08:48 +05301106 if err := f.techprofile[intfID].DeleteTechProfileInstance(ctx, tpID, uniPortName); err != nil {
Devmalya Paul495b94a2019-08-27 19:42:00 -04001107 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1108 return err
1109 }
1110 return nil
1111}
1112
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001113func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301114 if len(classifier) == 0 { // should never happen
1115 log.Error("Invalid classfier object")
1116 return 0
1117 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301118 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301119 var jsonData []byte
1120 var flowString string
1121 var err error
1122 // TODO: Do we need to marshall ??
1123 if jsonData, err = json.Marshal(classifier); err != nil {
1124 log.Error("Failed to encode classifier")
1125 return 0
1126 }
1127 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001128 if gemPortID != 0 {
1129 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301130 }
1131 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001132 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301133 hash := big.NewInt(0)
1134 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301135 generatedHash := hash.Uint64()
1136 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1137 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301138}
1139
npujarec5762e2020-01-01 14:08:48 +05301140func (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 +05301141 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001142 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001143 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1144 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1145 */
1146 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001147 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001148 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001149 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001150 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001151 // Get existing flows matching flowid for given subscriber from KV store
npujarec5762e2020-01-01 14:08:48 +05301152 existingFlows := f.resourceMgr.GetFlowIDInfo(ctx, intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001153 if existingFlows != nil {
1154 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001155 //for _, f := range *existingFlows {
1156 // flows = append(flows, f)
1157 //}
1158 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001159 }
1160 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 +05301161 return &flows
1162}
1163
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001164//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1165// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1166// var intfId uint32
1167// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1168// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1169// */
1170// if flow.AccessIntfId != -1 {
1171// intfId = uint32(flow.AccessIntfId)
1172// } else {
1173// intfId = uint32(flow.NetworkIntfId)
1174// }
1175// // Get existing flows matching flowid for given subscriber from KV store
1176// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1177// if existingFlows != nil {
1178// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1179// for _, f := range *existingFlows {
1180// flows = append(flows, f)
1181// }
1182// }
1183// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1184// return &flows
1185//}
1186
npujarec5762e2020-01-01 14:08:48 +05301187func (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 -04001188 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
npujarec5762e2020-01-01 14:08:48 +05301189 if err := f.resourceMgr.UpdateFlowIDInfo(ctx, intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001190 log.Debug("Error while Storing flow into KV store")
1191 return err
1192 }
1193 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301194 return nil
1195}
1196
npujarec5762e2020-01-01 14:08:48 +05301197func (f *OpenOltFlowMgr) addFlowToDevice(ctx context.Context, logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) bool {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001198
1199 var intfID uint32
1200 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1201 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1202 */
1203 if deviceFlow.AccessIntfId != -1 {
1204 intfID = uint32(deviceFlow.AccessIntfId)
1205 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001206 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001207 intfID = uint32(deviceFlow.NetworkIntfId)
1208 }
1209
manikkaraj kbf256be2019-03-25 00:13:48 +05301210 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1211 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001212
1213 st, _ := status.FromError(err)
1214 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001215 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
Girish Gowdra3d633032019-12-10 16:37:05 +05301216 return true
manikkaraj kbf256be2019-03-25 00:13:48 +05301217 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001218
1219 if err != nil {
1220 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
npujarec5762e2020-01-01 14:08:48 +05301221 f.resourceMgr.FreeFlowID(ctx, intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001222 return false
1223 }
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301224 if deviceFlow.GemportId != -1 {
1225 // No need to register the flow if it is a trap on nni flow.
npujarec5762e2020-01-01 14:08:48 +05301226 f.registerFlow(ctx, logicalFlow, deviceFlow)
Abhilash Laxmeshwar6d1acb92020-01-17 15:43:03 +05301227 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301228 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001229 return true
1230}
1231
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001232func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) bool {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001233 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1234 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1235 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001236 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1237 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1238 //Assume the flow is removed
1239 return true
1240 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001241 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
1242 return false
serkant.uluderya245caba2019-09-24 23:15:29 -07001243
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001244 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001245 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +05301246 return true
1247}
1248
1249/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1250 //update core flows_proxy : flows_proxy.update('/', flows)
1251}
1252
1253func generateStoredId(flowId uint32, direction string)uint32{
1254
David K. Bainbridge82efc492019-09-04 09:57:11 -07001255 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301256 log.Debug("Upstream flow shifting flowid")
1257 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001258 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301259 log.Debug("Downstream flow not shifting flowid")
1260 return flowId
1261 }else{
1262 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1263 return flowId
1264 }
1265}
1266
1267*/
1268
npujarec5762e2020-01-01 14:08:48 +05301269func (f *OpenOltFlowMgr) addLLDPFlow(ctx context.Context, flow *ofp.OfpFlowStats, portNo uint32) {
Humera Kouser94d7a842019-08-25 19:04:32 -04001270
1271 classifierInfo := make(map[string]interface{})
1272 actionInfo := make(map[string]interface{})
1273
1274 classifierInfo[EthType] = uint32(LldpEthType)
1275 classifierInfo[PacketTagType] = Untagged
1276 actionInfo[TrapToHost] = true
1277
1278 // LLDP flow is installed to trap LLDP packets on the NNI port.
1279 // We manage flow_id resource pool on per PON port basis.
1280 // Since this situation is tricky, as a hack, we pass the NNI port
1281 // index (network_intf_id) as PON port Index for the flow_id resource
1282 // pool. Also, there is no ONU Id available for trapping LLDP packets
1283 // on NNI port, use onu_id as -1 (invalid)
1284 // ****************** CAVEAT *******************
1285 // This logic works if the NNI Port Id falls within the same valid
1286 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1287 // we need to have a re-look at this.
1288 // *********************************************
1289
1290 var onuID = -1
1291 var uniID = -1
1292 var gemPortID = -1
1293
1294 var networkInterfaceID = IntfIDFromNniPortNum(portNo)
1295 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301296 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001297 log.Debug("Flow-exists--not-re-adding")
1298 return
1299 }
npujarec5762e2020-01-01 14:08:48 +05301300 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001301
1302 if err != nil {
1303 log.Errorw("Flow id unavailable for LLDP traponNNI flow", log.Fields{"error": err})
1304 return
1305 }
1306 var classifierProto *openoltpb2.Classifier
1307 var actionProto *openoltpb2.Action
1308 if classifierProto = makeOpenOltClassifierField(classifierInfo); classifierProto == nil {
1309 log.Error("Error in making classifier protobuf for LLDP trap on nni flow")
1310 return
1311 }
1312 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1313 if actionProto = makeOpenOltActionField(actionInfo); actionProto == nil {
1314 log.Error("Error in making action protobuf for LLDP trap on nni flow")
1315 return
1316 }
1317 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1318
1319 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1320 OnuId: int32(onuID), // OnuId not required
1321 UniId: int32(uniID), // UniId not used
1322 FlowId: flowID,
1323 FlowType: Downstream,
1324 NetworkIntfId: int32(networkInterfaceID),
1325 GemportId: int32(gemPortID),
1326 Classifier: classifierProto,
1327 Action: actionProto,
1328 Priority: int32(flow.Priority),
1329 Cookie: flow.Cookie,
1330 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +05301331 if ok := f.addFlowToDevice(ctx, flow, &downstreamflow); ok {
Humera Kouser94d7a842019-08-25 19:04:32 -04001332 log.Debug("LLDP trap on NNI flow added to device successfully")
npujarec5762e2020-01-01 14:08:48 +05301333 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, flow.Id)
1334 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
Humera Kouser94d7a842019-08-25 19:04:32 -04001335 int32(onuID),
1336 int32(uniID),
1337 flowID, flowsToKVStore); err != nil {
1338 log.Errorw("Error uploading LLDP flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1339 }
1340 }
1341 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301342}
1343
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301344func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001345 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1346}
1347
1348//getOnuChildDevice to fetch onu
1349func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1350 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1351 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
1352 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301353 if onuDevice == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001354 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301355 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +05301356 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301357 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1358 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301359}
1360
1361func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001362 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301363 return nil
1364}
1365
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001366func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1367 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301368}
1369
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001370func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001371 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001372 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001373 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001374 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001375}
1376
Girish Gowdra6b130582019-11-20 16:45:20 +05301377func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1378 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1379 if err != nil {
1380 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1381 return err
1382 }
1383
1384 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1385 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1386 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1387 delGemPortMsg,
1388 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1389 f.deviceHandler.deviceType,
1390 onuDevice.Type,
1391 onuDevice.Id,
1392 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1393 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1394 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1395 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1396 return sendErr
1397 }
1398 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1399 return nil
1400}
1401
1402func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1403 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1404 if err != nil {
1405 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1406 return err
1407 }
1408
1409 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1410 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1411 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1412 delTcontMsg,
1413 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1414 f.deviceHandler.deviceType,
1415 onuDevice.Type,
1416 onuDevice.Id,
1417 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1418 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1419 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1420 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1421 return sendErr
1422 }
1423 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1424 return nil
1425}
1426
Girish Gowdra3d633032019-12-10 16:37:05 +05301427func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1428 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1429 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1430 if val.(int) > 0 {
1431 pnFlDels := val.(int) - 1
1432 if pnFlDels > 0 {
1433 log.Debugw("flow delete succeeded, more pending",
1434 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1435 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1436 } else {
1437 log.Debugw("all pending flow deletes handled, removing entry from map",
1438 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1439 f.pendingFlowDelete.Delete(pnFlDelKey)
1440 }
1441 }
1442 } else {
1443 log.Debugw("no pending delete flows found",
1444 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1445
1446 }
1447
1448}
1449
Girish Gowdrac3037402020-01-22 20:29:53 +05301450// Once the gemport is released for a given onu, it also has to be cleared from local cache
1451// which was used for deriving the gemport->logicalPortNo during packet-in.
1452// Otherwise stale info continues to exist after gemport is freed and wrong logicalPortNo
1453// is conveyed to ONOS during packet-in OF message.
1454func (f *OpenOltFlowMgr) deleteGemPortFromLocalCache(intfID uint32, onuID uint32, gemPortID uint32) {
1455 f.lockCache.Lock()
1456 defer f.lockCache.Unlock()
1457 onugem := f.onuGemInfo[intfID]
1458 for _, onu := range onugem {
1459 if onu.OnuID == onuID {
1460 for i, gem := range onu.GemPorts {
1461 // If the gemport is found, delete it from local cache.
1462 if gem == gemPortID {
1463 onu.GemPorts = append(onu.GemPorts[:i], onu.GemPorts[i+1:]...)
1464 log.Debugw("removed gemport from local cache",
1465 log.Fields{"intfID": intfID, "onuID": onuID, "gemPortID": gemPortID})
1466 break
1467 }
1468 }
1469 break
1470 }
1471 }
1472}
1473
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301474//clearResources clears pon resources in kv store and the device
npujarec5762e2020-01-01 14:08:48 +05301475func (f *OpenOltFlowMgr) clearResources(ctx context.Context, flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301476 gemPortID int32, flowID uint32, flowDirection string,
1477 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001478
Chaitrashree G S90a17952019-11-14 21:51:21 -05001479 tpID, err := getTpIDFromFlow(flow)
1480 if err != nil {
1481 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1482 return err
1483 }
Gamze Abakafee36392019-10-03 11:17:24 +00001484
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001485 if len(updatedFlows) >= 0 {
1486 // There are still flows referencing the same flow_id.
1487 // So the flow should not be freed yet.
1488 // For ex: Case of HSIA where same flow is shared
1489 // between DS and US.
npujarec5762e2020-01-01 14:08:48 +05301490 f.updateFlowInfoToKVStore(ctx, int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001491 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301492 // Do this for subscriber flows only (not trap from NNI flows)
1493 if onuID != -1 && uniID != -1 {
1494 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1495 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1496 log.Debugw("creating entry for pending flow delete",
1497 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1498 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1499 } else {
1500 pnFlDels := val.(int) + 1
1501 log.Debugw("updating flow delete entry",
1502 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1503 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1504 }
1505
1506 defer f.deletePendingFlows(Intf, onuID, uniID)
1507 }
1508
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301509 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
npujarec5762e2020-01-01 14:08:48 +05301510 f.resourceMgr.FreeFlowID(ctx, Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001511
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301512 uni := getUniPortPath(Intf, onuID, uniID)
1513 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001514 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
npujarec5762e2020-01-01 14:08:48 +05301515 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(ctx, tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001516 if err != nil { // This should not happen, something wrong in KV backend transaction
1517 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301518 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001519 }
1520 if techprofileInst == nil {
1521 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301522 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001523 }
1524
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301525 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001526 if f.isGemPortUsedByAnotherFlow(gemPK) {
1527 flowIDs := f.flowsUsedByGemPort[gemPK]
1528 for i, flowIDinMap := range flowIDs {
1529 if flowIDinMap == flowID {
1530 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301531 // everytime flowsUsedByGemPort cache is updated the same should be updated
1532 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001533 f.flowsUsedByGemPort[gemPK] = flowIDs
npujarec5762e2020-01-01 14:08:48 +05301534 f.resourceMgr.UpdateFlowIDsForGem(ctx, Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001535 break
1536 }
1537 }
1538 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301539 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001540 }
Gamze Abakafee36392019-10-03 11:17:24 +00001541 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
npujarec5762e2020-01-01 14:08:48 +05301542 f.resourceMgr.RemoveGemPortIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001543 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1544 // 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 +05301545 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(ctx, uint32(gemPortID), Intf)
Girish Gowdrac3037402020-01-22 20:29:53 +05301546 f.deleteGemPortFromLocalCache(Intf, uint32(onuID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001547 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301548 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1549 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001550 delete(f.flowsUsedByGemPort, gemPK)
npujarec5762e2020-01-01 14:08:48 +05301551 f.resourceMgr.DeleteFlowIDsForGem(ctx, Intf, uint32(gemPortID))
1552 f.resourceMgr.FreeGemPortID(ctx, Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001553 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301554 // Delete the gem port on the ONU.
1555 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1556 log.Errorw("error processing delete gem-port towards onu",
1557 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1558 }
Gamze Abakafee36392019-10-03 11:17:24 +00001559
npujarec5762e2020-01-01 14:08:48 +05301560 ok, _ := f.isTechProfileUsedByAnotherGem(ctx, Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001561 if !ok {
npujarec5762e2020-01-01 14:08:48 +05301562 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, Intf, uint32(onuID), uint32(uniID), tpID)
1563 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1564 f.RemoveSchedulerQueues(ctx, schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1565 f.DeleteTechProfileInstance(ctx, Intf, uint32(onuID), uint32(uniID), "", tpID)
1566 f.resourceMgr.FreeAllocID(ctx, Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301567 // Delete the TCONT on the ONU.
1568 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1569 log.Errorw("error processing delete tcont towards onu",
1570 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1571 }
Gamze Abakafee36392019-10-03 11:17:24 +00001572 }
1573 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001574 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301575 return nil
1576}
1577
npujarec5762e2020-01-01 14:08:48 +05301578func (f *OpenOltFlowMgr) clearFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) {
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301579
1580 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
Esin Karamanccb714b2019-11-29 15:02:06 +00001581
1582 if flowDirection == Multicast {
npujarec5762e2020-01-01 14:08:48 +05301583 f.clearMulticastFlowFromResourceManager(ctx, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001584 return
1585 }
1586
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301587 var updatedFlows []rsrcMgr.FlowInfo
1588 var flowID uint32
1589 var onuID, uniID int32
1590 classifierInfo := make(map[string]interface{})
1591
1592 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1593 if err != nil {
1594 log.Error(err)
1595 return
1596 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301597
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301598 onuID = int32(onu)
1599 uniID = int32(uni)
1600
1601 for _, field := range flows.GetOfbFields(flow) {
1602 if field.Type == flows.IP_PROTO {
1603 classifierInfo[IPProto] = field.GetIpProto()
1604 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1605 }
1606 }
1607 log.Debugw("Extracted access info from flow to be deleted",
1608 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1609
1610 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1611 onuID = -1
1612 uniID = -1
1613 log.Debug("Trap on nni flow set oni, uni to -1")
1614 Intf = IntfIDFromNniPortNum(inPort)
1615 }
npujarec5762e2020-01-01 14:08:48 +05301616 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, Intf, onuID, uniID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301617 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301618 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, Intf, onuID, uniID, flowID)
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301619 if flowInfo == nil {
1620 log.Debugw("No FlowInfo found found in KV store",
1621 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1622 return
1623 }
1624 updatedFlows = nil
1625 for _, flow := range *flowInfo {
1626 updatedFlows = append(updatedFlows, flow)
1627 }
1628
1629 for i, storedFlow := range updatedFlows {
1630 if flow.Id == storedFlow.LogicalFlowID {
1631 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1632 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
1633 if ok := f.removeFlowFromDevice(&removeFlowMessage); ok {
1634 log.Debug("Flow removed from device successfully")
1635 //Remove the Flow from FlowInfo
1636 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301637 err = f.clearResources(ctx, flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301638 flowID, flowDirection, portNum, updatedFlows)
1639 if err != nil {
1640 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
1641 return
1642 }
1643 } else {
1644 log.Error("Failed to remove flow from device")
1645 return
1646 }
1647 }
1648 }
1649 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001650}
1651
Esin Karamanccb714b2019-11-29 15:02:06 +00001652//clearMulticastFlowFromResourceManager removes a multicast flow from the KV store and
1653// clears resources reserved for this multicast flow
npujarec5762e2020-01-01 14:08:48 +05301654func (f *OpenOltFlowMgr) clearMulticastFlowFromResourceManager(ctx context.Context, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001655 classifierInfo := make(map[string]interface{})
1656 formulateClassifierInfoFromFlow(classifierInfo, flow)
npujarec5762e2020-01-01 14:08:48 +05301657 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001658
1659 if err != nil {
1660 log.Warnw("No inPort found. Cannot release resources of the multicast flow.", log.Fields{"flowId:": flow.Id})
1661 return
1662 }
1663
1664 networkInterfaceID := IntfIDFromNniPortNum(inPort)
1665 var onuID = int32(NoneOnuID)
1666 var uniID = int32(NoneUniID)
1667 var flowID uint32
1668 var updatedFlows []rsrcMgr.FlowInfo
1669
npujarec5762e2020-01-01 14:08:48 +05301670 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ctx, networkInterfaceID, onuID, uniID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001671
1672 for _, flowID = range flowIds {
npujarec5762e2020-01-01 14:08:48 +05301673 flowInfo := f.resourceMgr.GetFlowIDInfo(ctx, networkInterfaceID, onuID, uniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001674 if flowInfo == nil {
1675 log.Debugw("No multicast FlowInfo found in the KV store",
1676 log.Fields{"Intf": networkInterfaceID, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1677 continue
1678 }
1679 updatedFlows = nil
1680 for _, flow := range *flowInfo {
1681 updatedFlows = append(updatedFlows, flow)
1682 }
1683 for i, storedFlow := range updatedFlows {
1684 if flow.Id == storedFlow.LogicalFlowID {
1685 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1686 log.Debugw("Multicast flow to be deleted", log.Fields{"flow": storedFlow})
1687 //remove from device
1688 if ok := f.removeFlowFromDevice(&removeFlowMessage); !ok {
1689 log.Errorw("Failed to remove multicast flow from device", log.Fields{"flowId": flow.Id})
1690 return
1691 }
1692 log.Debugw("Multicast flow removed from device successfully", log.Fields{"flowId": flow.Id})
1693 //Remove the Flow from FlowInfo
1694 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
npujarec5762e2020-01-01 14:08:48 +05301695 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID), NoneOnuID, NoneUniID, flowID, &updatedFlows); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001696 log.Error("Failed to delete multicast flow from the KV store", log.Fields{"flow": storedFlow, "err": err})
1697 return
1698 }
1699 //release flow id
1700 log.Debugw("Releasing multicast flow id", log.Fields{"flowId": flowID, "interfaceID": networkInterfaceID})
npujarec5762e2020-01-01 14:08:48 +05301701 f.resourceMgr.FreeFlowID(ctx, uint32(networkInterfaceID), NoneOnuID, NoneUniID, flowID)
Esin Karamanccb714b2019-11-29 15:02:06 +00001702 }
1703 }
1704 }
1705}
1706
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001707//RemoveFlow removes the flow from the device
npujarec5762e2020-01-01 14:08:48 +05301708func (f *OpenOltFlowMgr) RemoveFlow(ctx context.Context, flow *ofp.OfpFlowStats) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001709 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301710 var direction string
1711 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001712
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301713 for _, action := range flows.GetActions(flow) {
1714 if action.Type == flows.OUTPUT {
1715 if out := action.GetOutput(); out != nil {
1716 actionInfo[Output] = out.GetPort()
1717 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1718 } else {
1719 log.Error("Invalid output port in action")
1720 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001721 }
1722 }
1723 }
Esin Karamanccb714b2019-11-29 15:02:06 +00001724
1725 if flows.HasGroup(flow) {
1726 direction = Multicast
1727 } else if IsUpstream(actionInfo[Output].(uint32)) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301728 direction = Upstream
1729 } else {
1730 direction = Downstream
1731 }
npujarec5762e2020-01-01 14:08:48 +05301732 f.clearFlowFromResourceManager(ctx, flow, direction) //TODO: Take care of the limitations
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301733
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001734 return
1735}
1736
Girish Gowdra3d633032019-12-10 16:37:05 +05301737func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1738 uniID uint32, ch chan bool) {
1739 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1740 for {
1741 select {
1742 case <-time.After(20 * time.Millisecond):
1743 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1744 log.Debug("pending flow deletes completed")
1745 ch <- true
1746 return
1747 }
1748 case <-ctx.Done():
1749 log.Error("flow delete wait handler routine canceled")
1750 return
1751 }
1752 }
1753}
1754
Esin Karamanae41e2b2019-12-17 18:13:13 +00001755//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1756func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1757 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1758 if ethType, ok := classifierInfo[EthType]; ok {
1759 if ethType.(uint32) == IPv4EthType {
1760 if ipProto, ok := classifierInfo[IPProto]; ok {
1761 if ipProto.(uint32) == IgmpProto {
1762 return true
1763 }
1764 }
1765 }
1766 }
1767 }
1768 return false
1769}
1770
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001771// AddFlow add flow to device
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301772// nolint: gocyclo
npujarec5762e2020-01-01 14:08:48 +05301773func (f *OpenOltFlowMgr) AddFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001774 classifierInfo := make(map[string]interface{})
1775 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001776 var UsMeterID uint32
1777 var DsMeterID uint32
1778
1779 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001780 formulateClassifierInfoFromFlow(classifierInfo, flow)
1781
1782 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1783 if err != nil {
1784 // Error logging is already done in the called function
1785 // So just return in case of error
1786 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301787 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001788
Esin Karamanccb714b2019-11-29 15:02:06 +00001789 if flows.HasGroup(flow) {
1790 // handle multicast flow
npujarec5762e2020-01-01 14:08:48 +05301791 f.handleFlowWithGroup(ctx, actionInfo, classifierInfo, flow)
Esin Karamanccb714b2019-11-29 15:02:06 +00001792 return
1793 }
1794
manikkaraj k17652a72019-05-06 09:06:36 -04001795 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001796 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1797 if err != nil {
1798 // error if any, already logged in the called function
1799 return
manikkaraj k17652a72019-05-06 09:06:36 -04001800 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001801
David K. Bainbridge82efc492019-09-04 09:57:11 -07001802 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1803 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001804
Humera Kouser94d7a842019-08-25 19:04:32 -04001805 if ethType, ok := classifierInfo[EthType]; ok {
1806 if ethType.(uint32) == LldpEthType {
1807 log.Info("Adding LLDP flow")
npujarec5762e2020-01-01 14:08:48 +05301808 f.addLLDPFlow(ctx, flow, portNo)
Humera Kouser94d7a842019-08-25 19:04:32 -04001809 return
1810 }
1811 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001812 if ipProto, ok := classifierInfo[IPProto]; ok {
1813 if ipProto.(uint32) == IPProtoDhcp {
1814 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
Naga Manjunathb8438aa2020-01-02 17:52:33 +05301815 if udpSrc.(uint32) == uint32(67) || udpSrc.(uint32) == uint32(546) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001816 log.Debug("trap-dhcp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301817 f.addDHCPTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001818 return
1819 }
1820 }
1821 }
1822 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001823 if isIgmpTrapDownstreamFlow(classifierInfo) {
1824 log.Debug("trap-igmp-from-nni-flow")
npujarec5762e2020-01-01 14:08:48 +05301825 f.addIgmpTrapFlowOnNNI(ctx, flow, classifierInfo, portNo)
Esin Karamanae41e2b2019-12-17 18:13:13 +00001826 return
1827 }
A R Karthick1f85b802019-10-11 05:06:05 +00001828
1829 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
npujarec5762e2020-01-01 14:08:48 +05301830 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001831
Chaitrashree G S90a17952019-11-14 21:51:21 -05001832 TpID, err := getTpIDFromFlow(flow)
1833 if err != nil {
1834 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1835 return
1836 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001837 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001838 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001839 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001840 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1841 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001842 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001843 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1844
1845 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301846
1847 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1848 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1849 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 +05301850 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301851 } else {
Girish Gowdra3d633032019-12-10 16:37:05 +05301852 pendingFlowDelComplete := make(chan bool)
1853 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1854 select {
1855 case <-pendingFlowDelComplete:
1856 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
npujarec5762e2020-01-01 14:08:48 +05301857 f.divideAndAddFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdra3d633032019-12-10 16:37:05 +05301858
1859 case <-time.After(10 * time.Second):
1860 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1861 }
1862 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001863}
1864
Esin Karamanccb714b2019-11-29 15:02:06 +00001865// handleFlowWithGroup adds multicast flow to the device.
npujarec5762e2020-01-01 14:08:48 +05301866func (f *OpenOltFlowMgr) handleFlowWithGroup(ctx context.Context, actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001867 classifierInfo[PacketTagType] = DoubleTag
1868 log.Debugw("add-multicast-flow", log.Fields{"classifierInfo": classifierInfo, "actionInfo": actionInfo})
1869
npujarec5762e2020-01-01 14:08:48 +05301870 inPort, err := f.getInPortOfMulticastFlow(ctx, classifierInfo)
Esin Karamanccb714b2019-11-29 15:02:06 +00001871 if err != nil {
1872 log.Warnw("No inPort found. Ignoring multicast flow.", log.Fields{"flowId:": flow.Id})
1873 return
1874 }
1875 //replace ipDst with ethDst
1876 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok &&
1877 flows.IsMulticastIp(ipv4Dst.(uint32)) {
1878 // replace ipv4_dst classifier with eth_dst
1879 multicastMac := flows.ConvertToMulticastMacBytes(ipv4Dst.(uint32))
1880 delete(classifierInfo, Ipv4Dst)
1881 delete(classifierInfo, EthType)
1882 classifierInfo[EthDst] = multicastMac
1883 log.Debugw("multicast-ip-to-mac-conversion-success", log.Fields{"ip:": ipv4Dst.(uint32), "mac:": multicastMac})
1884 }
1885
1886 var onuID = NoneOnuID
1887 var uniID = NoneUniID
1888 var gemPortID = NoneGemPortID
1889
1890 networkInterfaceID := IntfIDFromNniPortNum(inPort)
1891
1892 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05301893 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Esin Karamanccb714b2019-11-29 15:02:06 +00001894 log.Debugw("multicast-flow-exists--not-re-adding", log.Fields{"classifierInfo": classifierInfo})
1895 return
1896 }
npujarec5762e2020-01-01 14:08:48 +05301897 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanccb714b2019-11-29 15:02:06 +00001898 if err != nil {
1899 log.Errorw("Flow id unavailable for multicast flow", log.Fields{"error": err})
1900 return
1901 }
1902 var classifierProto *openoltpb2.Classifier
1903 if classifierProto = makeOpenOltClassifierField(classifierInfo); classifierProto == nil {
1904 log.Error("Error in making classifier protobuf for multicast flow")
1905 return
1906 }
1907 groupID := actionInfo[GroupID].(uint32)
1908 multicastFlow := openoltpb2.Flow{
1909 FlowId: flowID,
1910 FlowType: Multicast,
1911 NetworkIntfId: int32(networkInterfaceID),
1912 GroupId: groupID,
1913 Classifier: classifierProto,
1914 Priority: int32(flow.Priority),
1915 Cookie: flow.Cookie}
1916
npujarec5762e2020-01-01 14:08:48 +05301917 if ok := f.addFlowToDevice(ctx, flow, &multicastFlow); ok {
Esin Karamanccb714b2019-11-29 15:02:06 +00001918 log.Debug("multicast flow added to device successfully")
1919 //get cached group
npujarec5762e2020-01-01 14:08:48 +05301920 group, _, err := f.GetFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001921 if err == nil {
1922 //calling groupAdd to set group members after multicast flow creation
npujarec5762e2020-01-01 14:08:48 +05301923 if f.ModifyGroup(ctx, group) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001924 //cached group can be removed now
npujarec5762e2020-01-01 14:08:48 +05301925 f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, groupID, true)
Esin Karamanccb714b2019-11-29 15:02:06 +00001926 }
1927 }
1928
npujarec5762e2020-01-01 14:08:48 +05301929 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &multicastFlow, flowStoreCookie, MulticastFlow, flowID, flow.Id)
1930 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
Esin Karamanccb714b2019-11-29 15:02:06 +00001931 int32(onuID),
1932 int32(uniID),
1933 flowID, flowsToKVStore); err != nil {
1934 log.Errorw("Error uploading multicast flow into KV store", log.Fields{"flow": multicastFlow, "error": err})
1935 }
1936 }
1937 return
1938}
1939
1940//getInPortOfMulticastFlow return inPort criterion if exists; returns NNI interface of the device otherwise
npujarec5762e2020-01-01 14:08:48 +05301941func (f *OpenOltFlowMgr) getInPortOfMulticastFlow(ctx context.Context, classifierInfo map[string]interface{}) (uint32, error) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001942 if _, ok := classifierInfo[InPort]; ok {
1943 return classifierInfo[InPort].(uint32), nil
1944 }
1945 // find first NNI port of the device
npujarec5762e2020-01-01 14:08:48 +05301946 nniPorts, e := f.resourceMgr.GetNNIFromKVStore(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00001947 if e == nil && len(nniPorts) > 0 {
1948 return nniPorts[0], nil
1949 }
1950 return 0, errors.New("cannot find NNI port of device")
1951}
1952
1953// AddGroup add or update the group
npujarec5762e2020-01-01 14:08:48 +05301954func (f *OpenOltFlowMgr) AddGroup(ctx context.Context, group *ofp.OfpGroupEntry) {
Esin Karamanccb714b2019-11-29 15:02:06 +00001955 log.Infow("add-group", log.Fields{"group": group})
1956 if group == nil {
1957 log.Warn("skipping nil group")
1958 return
1959 }
1960
1961 groupToOlt := openoltpb2.Group{
1962 GroupId: group.Desc.GroupId,
1963 Command: openoltpb2.Group_SET_MEMBERS,
1964 Action: f.buildGroupAction(),
1965 }
1966
1967 log.Debugw("Sending group to device", log.Fields{"groupToOlt": groupToOlt})
npujarec5762e2020-01-01 14:08:48 +05301968 _, err := f.deviceHandler.Client.PerformGroupOperation(ctx, &groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00001969 if err != nil {
1970 log.Errorw("add-group operation failed", log.Fields{"err": err, "groupToOlt": groupToOlt})
1971 return
1972 }
1973 // group members not created yet. So let's store the group
npujarec5762e2020-01-01 14:08:48 +05301974 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, true); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00001975 log.Errorw("Group cannot be stored in KV store", log.Fields{"groupId": group.Desc.GroupId, "err": err})
1976 } else {
1977 log.Debugw("add-group operation performed on the device successfully ", log.Fields{"groupToOlt": groupToOlt})
1978 }
1979}
1980
1981//buildGroupAction creates and returns a group action
1982func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
1983 var actionCmd openoltpb2.ActionCmd
1984 var action openoltpb2.Action
1985 action.Cmd = &actionCmd
1986 //pop outer vlan
1987 action.Cmd.RemoveOuterTag = true
1988 return &action
1989}
1990
1991// ModifyGroup updates the group
npujarec5762e2020-01-01 14:08:48 +05301992func (f *OpenOltFlowMgr) ModifyGroup(ctx context.Context, group *ofp.OfpGroupEntry) bool {
Esin Karamanccb714b2019-11-29 15:02:06 +00001993 log.Infow("modify-group", log.Fields{"group": group})
1994 if group == nil || group.Desc == nil {
1995 log.Warn("cannot modify group; group is nil")
1996 return false
1997 }
1998
1999 new := f.buildGroup(group.Desc.GroupId, group.Desc.Buckets)
2000 //get existing members of the group
npujarec5762e2020-01-01 14:08:48 +05302001 val, groupExists, err := f.GetFlowGroupFromKVStore(ctx, group.Desc.GroupId, false)
Esin Karamanccb714b2019-11-29 15:02:06 +00002002
2003 if err != nil {
2004 log.Errorw("Failed to retrieve the group from the store. Cannot modify group.",
2005 log.Fields{"groupId": group.Desc.GroupId, "err": err})
2006 return false
2007 }
2008
2009 var current *openoltpb2.Group
2010 if groupExists {
2011 // group already exists
2012 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
2013 log.Debugw("modify-group: group exists.", log.Fields{"current": val, "new": group})
2014 } else {
2015 current = f.buildGroup(group.Desc.GroupId, nil)
2016 }
2017
2018 log.Debugw("modify-group: comparing current and new.", log.Fields{"current": current, "new": new})
2019 // check if the buckets are identical
2020 bucketsIdentical := f.bucketsIdentical(current, new)
2021
2022 isSuccess := true
2023 if !bucketsIdentical {
2024 groupToOlt := openoltpb2.Group{
2025 GroupId: group.Desc.GroupId,
2026 Command: openoltpb2.Group_SET_MEMBERS,
2027 Members: new.Members,
2028 Action: f.buildGroupAction(),
2029 }
2030
2031 if err := f.callGroupAdd(&groupToOlt); err != nil {
2032 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2033 log.Fields{"group": group})
2034 isSuccess = false
2035 }
2036 }
2037
2038 if isSuccess {
npujarec5762e2020-01-01 14:08:48 +05302039 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002040 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2041 }
2042 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
2043 }
2044 return isSuccess
2045}
2046
2047//bucketsIdentical returns true if groups are identical; false otherwise
2048func (f *OpenOltFlowMgr) bucketsIdentical(current *openoltpb2.Group, new *openoltpb2.Group) bool {
2049 if current.GroupId == new.GroupId &&
2050 len(new.Members) == len(current.Members) {
2051 diff := f.findDiff(current, new)
2052 if diff == nil || len(diff) < 1 {
2053 log.Infow("modify-group: current and new buckets are the same. Won't send SET_MEMBERS again.",
2054 log.Fields{"groupId:": current.GroupId})
2055 return true
2056 }
2057 }
2058 return false
2059}
2060
2061//findDiff compares group members and finds members which only exists in groups2
2062func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2063 var members []*openoltpb2.GroupMember
2064 for _, bucket := range group2.Members {
2065 if !f.contains(group1.Members, bucket) {
2066 // bucket does not exist and must be added
2067 members = append(members, bucket)
2068 }
2069 }
2070 return members
2071}
2072
2073//contains returns true if the members list contains the given member; false otherwise
2074func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2075 for _, groupMember := range members {
2076 if groupMember.InterfaceId == member.InterfaceId {
2077 return true
2078 }
2079 }
2080 return false
2081}
2082
2083//callGroupAdd call GroupAdd operation of openolt proto
2084func (f *OpenOltFlowMgr) callGroupAdd(group *openoltpb2.Group) error {
2085 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2086 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2087 if err != nil {
2088 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2089 }
2090 return err
2091}
2092
2093//buildGroup build openoltpb2.Group from given group id and bucket list
2094func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2095 group := openoltpb2.Group{
2096 GroupId: groupID}
2097 // create members of the group
2098 if buckets != nil {
2099 for _, ofBucket := range buckets {
2100 member := f.buildMember(ofBucket)
2101 if member != nil && !f.contains(group.Members, member) {
2102 group.Members = append(group.Members, member)
2103 }
2104 }
2105 }
2106 return &group
2107}
2108
2109//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2110func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2111 var outPort uint32
2112 outPortFound := false
2113 for _, ofAction := range ofBucket.Actions {
2114 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2115 outPort = ofAction.GetOutput().Port
2116 outPortFound = true
2117 }
2118 }
2119
2120 if !outPortFound {
2121 log.Debugw("bucket skipped since no out port found in it",
2122 log.Fields{"ofBucket": ofBucket})
2123 return nil
2124 }
2125 interfaceID := IntfIDFromUniPortNum(outPort)
2126 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2127 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2128 member := openoltpb2.GroupMember{
2129 InterfaceId: interfaceID,
2130 InterfaceType: openoltpb2.GroupMember_PON,
2131 GemPortId: groupInfo.gemPortID,
2132 Priority: groupInfo.servicePriority,
2133 }
2134 //add member to the group
2135 return &member
2136 }
2137 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2138 log.Fields{"ofBucket": ofBucket})
2139 return nil
2140}
2141
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002142//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002143func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002144
2145 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302146 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002147 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302148 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302149 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302150 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002151
Manikkaraj kb1d51442019-07-23 10:41:02 -04002152 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002153 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002154 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2155 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2156 tpDownloadMsg,
2157 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2158 f.deviceHandler.deviceType,
2159 onuDevice.Type,
2160 onuDevice.Id,
2161 onuDevice.ProxyAddress.DeviceId, "")
2162 if sendErr != nil {
2163 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2164 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2165 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2166 return sendErr
2167 }
2168 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302169 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302170}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002171
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302172//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302173func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302174
2175 f.lockCache.Lock()
2176 defer f.lockCache.Unlock()
2177 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2178 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
npujarec5762e2020-01-01 14:08:48 +05302179 if err := f.resourceMgr.AddOnuInfo(ctx, intfID, onu); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302180 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2181 return
2182 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002183 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2184}
2185
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302186//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302187func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302188 f.lockCache.Lock()
2189 defer f.lockCache.Unlock()
2190 onugem := f.onuGemInfo[intfID]
2191 // update the gem to the local cache as well as to kv strore
2192 for idx, onu := range onugem {
2193 if onu.OnuID == onuID {
2194 // check if gem already exists , else update the cache and kvstore
2195 for _, gem := range onu.GemPorts {
2196 if gem == gemPort {
2197 log.Debugw("Gem already in cache, no need to update cache and kv store",
2198 log.Fields{"gem": gemPort})
2199 return
2200 }
2201 }
2202 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2203 f.onuGemInfo[intfID] = onugem
2204 }
2205 }
npujarec5762e2020-01-01 14:08:48 +05302206 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302207 if err != nil {
2208 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002209 return
2210 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002211}
2212
2213// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002214
2215//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2216func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302217
2218 f.lockCache.Lock()
2219 defer f.lockCache.Unlock()
2220
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002221 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 +05302222 // get onuid from the onugem info cache
2223 onugem := f.onuGemInfo[intfID]
2224 for _, onu := range onugem {
2225 for _, gem := range onu.GemPorts {
2226 if gem == gemPortID {
2227 return onu.OnuID, nil
2228 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002229 }
2230 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002231 log.Errorw("onuid is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPort": gemPortID})
2232 return uint32(0), errors.New("key error, onuid is not found") // ONU ID 0 is not a valid one
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002233}
2234
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002235//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302236func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002237 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002238 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002239 var err error
2240
2241 if packetIn.IntfType == "pon" {
2242 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002243 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002244 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2245 return logicalPortNum, err
2246 }
2247 if packetIn.PortNo != 0 {
2248 logicalPortNum = packetIn.PortNo
2249 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002250 uniID := uint32(0) // FIXME - multi-uni support
2251 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002252 }
2253 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302254 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002255 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002256 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002257 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002258 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2259 "logicalPortNum": logicalPortNum,
2260 "IntfType": packetIn.IntfType,
2261 "packet": hex.EncodeToString(packetIn.Pkt),
2262 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002263 return logicalPortNum, nil
2264}
2265
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002266//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302267func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002268 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002269 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302270
2271 f.lockCache.Lock()
2272 defer f.lockCache.Unlock()
2273 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2274
2275 gemPortID, ok := f.packetInGemPort[pktInkey]
2276 if ok {
2277 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2278 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002279 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302280 //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 +05302281 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302282 if err == nil {
2283 if gemPortID != 0 {
2284 f.packetInGemPort[pktInkey] = gemPortID
2285 log.Debugw("Found gem port from kv store and updating cache with gemport",
2286 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2287 return gemPortID, nil
2288 }
2289 }
2290 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2291 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002292}
2293
npujarec5762e2020-01-01 14:08:48 +05302294func installFlowOnAllGemports(ctx context.Context,
2295 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002296 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
2297 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32),
npujarec5762e2020-01-01 14:08:48 +05302298 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302299 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
2300 classifier map[string]interface{}, action map[string]interface{}),
Manikkaraj kb1d51442019-07-23 10:41:02 -04002301 args map[string]uint32,
2302 classifier map[string]interface{}, action map[string]interface{},
2303 logicalFlow *ofp.OfpFlowStats,
2304 gemPorts []uint32,
2305 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002306 vlanID ...uint32) {
2307 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
2308 for _, gemPortID := range gemPorts {
Manikkaraj kb1d51442019-07-23 10:41:02 -04002309 if FlowType == HsiaFlow || FlowType == DhcpFlow {
npujarec5762e2020-01-01 14:08:48 +05302310 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002311 } else if FlowType == EapolFlow {
npujarec5762e2020-01-01 14:08:48 +05302312 f2(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], logicalFlow, args["allocId"], gemPortID, vlanID[0], classifier, action)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002313 } else {
2314 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2315 return
2316 }
2317 }
2318}
2319
npujarec5762e2020-01-01 14:08:48 +05302320func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002321 log.Debug("Adding trap-dhcp-of-nni-flow")
2322 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002323 classifier[PacketTagType] = DoubleTag
2324 action[TrapToHost] = true
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302325 var err error
2326 var networkInterfaceID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002327 /* We manage flowId resource pool on per PON port basis.
2328 Since this situation is tricky, as a hack, we pass the NNI port
2329 index (network_intf_id) as PON port Index for the flowId resource
2330 pool. Also, there is no ONU Id available for trapping DHCP packets
2331 on NNI port, use onu_id as -1 (invalid)
2332 ****************** CAVEAT *******************
2333 This logic works if the NNI Port Id falls within the same valid
2334 range of PON Port Ids. If this doesn't work for some OLT Vendor
2335 we need to have a re-look at this.
2336 *********************************************
2337 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002338 onuID := -1
2339 uniID := -1
2340 gemPortID := -1
2341 allocID := -1
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302342 networkInterfaceID, err = getNniIntfID(classifier, action)
2343 if err != nil {
2344 log.Error("Failed to get nniIntf ID")
2345 return
2346 }
2347
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002348 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302349 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002350 log.Debug("Flow-exists--not-re-adding")
2351 return
2352 }
npujarec5762e2020-01-01 14:08:48 +05302353 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002354 if err != nil {
2355 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
2356 return
2357 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002358 var classifierProto *openoltpb2.Classifier
2359 var actionProto *openoltpb2.Action
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002360 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
2361 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
2362 return
2363 }
2364 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
2365 if actionProto = makeOpenOltActionField(action); actionProto == nil {
2366 log.Error("Error in making action protobuf for dhcp trap on nni flow")
2367 return
2368 }
2369 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002370 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2371 OnuId: int32(onuID), // OnuId not required
2372 UniId: int32(uniID), // UniId not used
2373 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002374 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002375 AllocId: int32(allocID), // AllocId not used
2376 NetworkIntfId: int32(networkInterfaceID),
2377 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002378 Classifier: classifierProto,
2379 Action: actionProto,
2380 Priority: int32(logicalFlow.Priority),
2381 Cookie: logicalFlow.Cookie,
2382 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +05302383 if ok := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002384 log.Debug("DHCP trap on NNI flow added to device successfully")
npujarec5762e2020-01-01 14:08:48 +05302385 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2386 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002387 int32(onuID),
2388 int32(uniID),
2389 flowID, flowsToKVStore); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002390 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
2391 }
2392 }
2393 return
2394}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002395
Esin Karamanae41e2b2019-12-17 18:13:13 +00002396//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2397func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2398 var packetType string
2399 ovid, ivid := false, false
2400 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2401 vid := vlanID & VlanvIDMask
2402 if vid != ReservedVlan {
2403 ovid = true
2404 }
2405 }
2406 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2407 vid := uint32(metadata)
2408 if vid != ReservedVlan {
2409 ivid = true
2410 }
2411 }
2412 if ovid && ivid {
2413 packetType = DoubleTag
2414 } else if !ovid && !ivid {
2415 packetType = Untagged
2416 } else {
2417 packetType = SingleTag
2418 }
2419 return packetType
2420}
2421
2422//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
npujarec5762e2020-01-01 14:08:48 +05302423func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002424 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2425 action := make(map[string]interface{})
2426 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2427 action[TrapToHost] = true
2428 /* We manage flowId resource pool on per PON port basis.
2429 Since this situation is tricky, as a hack, we pass the NNI port
2430 index (network_intf_id) as PON port Index for the flowId resource
2431 pool. Also, there is no ONU Id available for trapping packets
2432 on NNI port, use onu_id as -1 (invalid)
2433 ****************** CAVEAT *******************
2434 This logic works if the NNI Port Id falls within the same valid
2435 range of PON Port Ids. If this doesn't work for some OLT Vendor
2436 we need to have a re-look at this.
2437 *********************************************
2438 */
2439 onuID := -1
2440 uniID := -1
2441 gemPortID := -1
2442 allocID := -1
2443 networkInterfaceID, err := getNniIntfID(classifier, action)
2444 if err != nil {
2445 log.Error("Failed to get nniIntf ID")
2446 return
2447 }
2448 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302449 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002450 log.Debug("igmp-flow-exists--not-re-adding")
2451 return
2452 }
npujarec5762e2020-01-01 14:08:48 +05302453 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002454 if err != nil {
2455 log.Errorw("IGMP flow id unavailable for trap-on-NNI flow", log.Fields{"error": err})
2456 return
2457 }
2458 var classifierProto *openoltpb2.Classifier
2459 var actionProto *openoltpb2.Action
2460 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
2461 log.Error("Error in making classifier protobuf for igmp trap on nni flow")
2462 return
2463 }
2464 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
2465 if actionProto = makeOpenOltActionField(action); actionProto == nil {
2466 log.Error("Error in making action protobuf for IGMP trap on nni flow")
2467 return
2468 }
2469 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2470 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2471 OnuId: int32(onuID), // OnuId not required
2472 UniId: int32(uniID), // UniId not used
2473 FlowId: flowID,
2474 FlowType: Downstream,
2475 AllocId: int32(allocID), // AllocId not used
2476 NetworkIntfId: int32(networkInterfaceID),
2477 GemportId: int32(gemPortID), // GemportId not used
2478 Classifier: classifierProto,
2479 Action: actionProto,
2480 Priority: int32(logicalFlow.Priority),
2481 Cookie: logicalFlow.Cookie,
2482 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +05302483 if ok := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); ok {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002484 log.Debug("IGMP Trap on NNI flow added to device successfully")
npujarec5762e2020-01-01 14:08:48 +05302485 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2486 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
Esin Karamanae41e2b2019-12-17 18:13:13 +00002487 int32(onuID),
2488 int32(uniID),
2489 flowID, flowsToKVStore); err != nil {
2490 log.Errorw("Error uploading igmp-trap-on-nni flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
2491 }
2492 }
2493 return
2494}
2495
salmansiddiqui7ac62132019-08-22 03:58:50 +00002496func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2497 if MeterID == 0 { // This should never happen
2498 log.Error("Invalid meter id")
2499 return "", errors.New("invalid meter id")
2500 }
2501 if Dir == tp_pb.Direction_UPSTREAM {
2502 return "upstream", nil
2503 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2504 return "downstream", nil
2505 }
2506 return "", nil
2507}
2508
npujarec5762e2020-01-01 14:08:48 +05302509func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002510 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2511 TpID uint32, uni string) {
2512 var gemPort uint32
2513 intfID := args[IntfID]
2514 onuID := args[OnuID]
2515 uniID := args[UniID]
2516 portNo := args[PortNo]
2517 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002518 if ipProto, ok := classifierInfo[IPProto]; ok {
2519 if ipProto.(uint32) == IPProtoDhcp {
2520 log.Info("Adding DHCP flow")
2521 if pcp, ok := classifierInfo[VlanPcp]; ok {
2522 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2523 tp_pb.Direction_UPSTREAM,
2524 pcp.(uint32))
2525 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302526 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002527 } else {
2528 //Adding DHCP upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302529 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002530 }
2531
2532 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002533 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2534 if pcp, ok := classifierInfo[VlanPcp]; ok {
2535 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2536 tp_pb.Direction_UPSTREAM,
2537 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302538 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002539 } else {
2540 //Adding IGMP upstream flow to all gem ports
npujarec5762e2020-01-01 14:08:48 +05302541 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002542 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002543 } else {
2544 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2545 return
2546 }
2547 } else if ethType, ok := classifierInfo[EthType]; ok {
2548 if ethType.(uint32) == EapEthType {
2549 log.Info("Adding EAPOL flow")
2550 var vlanID uint32
2551 if val, ok := classifierInfo[VlanVid]; ok {
2552 vlanID = (val.(uint32)) & VlanvIDMask
2553 } else {
2554 vlanID = DefaultMgmtVlan
2555 }
2556 if pcp, ok := classifierInfo[VlanPcp]; ok {
2557 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2558 tp_pb.Direction_UPSTREAM,
2559 pcp.(uint32))
2560
npujarec5762e2020-01-01 14:08:48 +05302561 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, flow, allocID, gemPort, vlanID, classifierInfo, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002562 } else {
npujarec5762e2020-01-01 14:08:48 +05302563 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002564 }
2565 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002566 } else if _, ok := actionInfo[PushVlan]; ok {
2567 log.Info("Adding upstream data rule")
2568 if pcp, ok := classifierInfo[VlanPcp]; ok {
2569 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2570 tp_pb.Direction_UPSTREAM,
2571 pcp.(uint32))
2572 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302573 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002574 } else {
2575 //Adding HSIA upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302576 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002577 }
2578 } else if _, ok := actionInfo[PopVlan]; ok {
2579 log.Info("Adding Downstream data rule")
2580 if pcp, ok := classifierInfo[VlanPcp]; ok {
2581 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002582 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002583 pcp.(uint32))
2584 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302585 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002586 } else {
2587 //Adding HSIA downstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302588 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002589 }
2590 } else {
2591 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2592 return
2593 }
2594 // Send Techprofile download event to child device in go routine as it takes time
2595 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2596}
2597
Gamze Abakafee36392019-10-03 11:17:24 +00002598func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2599 flowIDList := f.flowsUsedByGemPort[gemPK]
2600 if len(flowIDList) > 1 {
2601 return true
2602 }
2603 return false
2604}
2605
npujarec5762e2020-01-01 14:08:48 +05302606func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2607 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002608 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2609 for _, currentGemPort := range currentGemPorts {
2610 for _, tpGemPort := range tpGemPorts {
2611 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2612 return true, currentGemPort
2613 }
2614 }
2615 }
Girish Gowdra54934262019-11-13 14:19:55 +05302616 if tpInst.InstanceCtrl.Onu == "single-instance" {
2617 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302618 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2619 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302620
2621 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2622 // still be used on other uni ports.
2623 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2624 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302625 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302626 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302627 for i := 0; i < len(tpInstances); i++ {
2628 tpI := tpInstances[i]
2629 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302630 for _, tpGemPort := range tpGemPorts {
2631 if tpGemPort.GemportID != gemPortID {
2632 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2633 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302634 }
2635 }
2636 }
2637 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302638 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002639 return false, 0
2640}
2641
salmansiddiqui7ac62132019-08-22 03:58:50 +00002642func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002643 for _, field := range flows.GetOfbFields(flow) {
2644 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002645 classifierInfo[EthType] = field.GetEthType()
2646 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002647 } else if field.Type == flows.ETH_DST {
2648 classifierInfo[EthDst] = field.GetEthDst()
2649 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002650 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002651 classifierInfo[IPProto] = field.GetIpProto()
2652 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002653 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002654 classifierInfo[InPort] = field.GetPort()
2655 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002656 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302657 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002658 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002659 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002660 classifierInfo[VlanPcp] = field.GetVlanPcp()
2661 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002662 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002663 classifierInfo[UDPDst] = field.GetUdpDst()
2664 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002665 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002666 classifierInfo[UDPSrc] = field.GetUdpSrc()
2667 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002668 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002669 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2670 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002671 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002672 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2673 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002674 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002675 classifierInfo[Metadata] = field.GetTableMetadata()
2676 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002677 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002678 classifierInfo[TunnelID] = field.GetTunnelId()
2679 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2680 } else {
2681 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2682 return
2683 }
2684 }
2685}
2686
2687func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002688 for _, action := range flows.GetActions(flow) {
2689 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002690 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002691 actionInfo[Output] = out.GetPort()
2692 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002693 } else {
2694 log.Error("Invalid output port in action")
2695 return errors.New("invalid output port in action")
2696 }
Scott Baker355d1742019-10-24 10:57:52 -07002697 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002698 actionInfo[PopVlan] = true
2699 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002700 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002701 if out := action.GetPush(); out != nil {
2702 if tpid := out.GetEthertype(); tpid != 0x8100 {
2703 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2704 } else {
2705 actionInfo[PushVlan] = true
2706 actionInfo[TPID] = tpid
2707 log.Debugw("action-type-push-vlan",
2708 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2709 }
2710 }
Scott Baker355d1742019-10-24 10:57:52 -07002711 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002712 if out := action.GetSetField(); out != nil {
2713 if field := out.GetField(); field != nil {
2714 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
2715 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
2716 return errors.New("invalid openflow class")
2717 }
2718 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002719 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002720 }
2721 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002722 } else if action.Type == flows.GROUP {
2723 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002724 } else {
2725 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
2726 return errors.New("un supported action type")
2727 }
2728 }
2729 return nil
2730}
2731
Esin Karamanccb714b2019-11-29 15:02:06 +00002732func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2733 if ofbField := field.GetOfbField(); ofbField != nil {
2734 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2735 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2736 actionInfo[VlanVid] = vlan & 0xfff
2737 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2738 } else {
2739 log.Error("No Invalid vlan id in set vlan-vid action")
2740 }
2741 } else {
2742 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2743 }
2744 }
2745}
2746
2747func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2748 if action.GetGroup() == nil {
2749 log.Warn("No group entry found in the group action")
2750 } else {
2751 actionInfo[GroupID] = action.GetGroup().GroupId
2752 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2753 }
2754}
2755
salmansiddiqui7ac62132019-08-22 03:58:50 +00002756func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002757 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002758 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2759 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2760 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002761 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002762 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002763 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 +00002764 } else {
2765 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
2766 return errors.New("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
2767 }
2768 }
2769 } else {
2770 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2771 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002772 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002773 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002774 actionInfo[Output] = uniPort
2775 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 +00002776 } else {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002777 log.Debug("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid", log.Fields{"InPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002778 return errors.New("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid")
2779 }
2780 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2781 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002782 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002783 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002784 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2785 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002786 } else {
2787 log.Debug("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid", log.Fields{"InPort": classifierInfo[InPort].(uint32),
David K. Bainbridge82efc492019-09-04 09:57:11 -07002788 "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002789 return errors.New("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid")
2790 }
2791 }
2792 }
2793 return nil
2794}
Gamze Abakafee36392019-10-03 11:17:24 +00002795
Chaitrashree G S90a17952019-11-14 21:51:21 -05002796func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002797 /* Metadata 8 bytes:
2798 Most Significant 2 Bytes = Inner VLAN
2799 Next 2 Bytes = Tech Profile ID(TPID)
2800 Least Significant 4 Bytes = Port ID
2801 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2802 subscriber related flows.
2803 */
2804 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2805 if metadata == 0 {
Chaitrashree G S90a17952019-11-14 21:51:21 -05002806 log.Error("metadata-is-not-present-in-flow-which-is-mandatory")
2807 return 0, errors.New("metadata-is-not-present-in-flow-which-is-mandatory")
Gamze Abakafee36392019-10-03 11:17:24 +00002808 }
2809 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002810 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002811}
2812
2813func appendUnique(slice []uint32, item uint32) []uint32 {
2814 for _, sliceElement := range slice {
2815 if sliceElement == item {
2816 return slice
2817 }
2818 }
2819 return append(slice, item)
2820}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302821
2822// getNniIntfID gets nni intf id from the flow classifier/action
2823func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2824
2825 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2826 if portType == voltha.Port_PON_OLT {
2827 intfID := IntfIDFromNniPortNum(action[Output].(uint32))
2828 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2829 return intfID, nil
2830 } else if portType == voltha.Port_ETHERNET_NNI {
2831 intfID := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2832 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2833 return intfID, nil
2834 }
2835 return uint32(0), nil
2836}
2837
2838// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302839func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302840 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2841
2842 f.lockCache.Lock()
2843 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002844 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302845 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002846 if lookupGemPort == gemPort {
2847 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2848 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2849 return
2850 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302851 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002852 f.packetInGemPort[pktInkey] = gemPort
2853
npujarec5762e2020-01-01 14:08:48 +05302854 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002855 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 +05302856 return
2857}
2858
2859// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302860func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302861
2862 f.lockCache.Lock()
2863 defer f.lockCache.Unlock()
2864 onugem := f.onuGemInfo[intfID]
2865 for idx, onu := range onugem {
2866 if onu.OnuID == onuID {
2867 for _, uni := range onu.UniPorts {
2868 if uni == portNum {
2869 log.Debugw("uni already in cache, no need to update cache and kv store",
2870 log.Fields{"uni": portNum})
2871 return
2872 }
2873 }
2874 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2875 f.onuGemInfo[intfID] = onugem
2876 }
2877 }
npujarec5762e2020-01-01 14:08:48 +05302878 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302879}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302880
npujarec5762e2020-01-01 14:08:48 +05302881func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2882 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302883 if err != nil {
2884 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2885 return
2886 }
2887 for gem, FlowIDs := range flowIDsList {
2888 gemPK := gemPortKey{intf, uint32(gem)}
2889 f.flowsUsedByGemPort[gemPK] = FlowIDs
2890 }
2891 return
2892}
Esin Karamanccb714b2019-11-29 15:02:06 +00002893
2894//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2895//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302896func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2897 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002898 if err != nil {
2899 log.Error("Failed to get pon interface to multicast queue map")
2900 return
2901 }
2902 for intf, queueInfo := range storedMulticastQueueMap {
2903 q := queueInfoBrief{
2904 gemPortID: queueInfo[0],
2905 servicePriority: queueInfo[1],
2906 }
2907 f.interfaceToMcastQueueMap[intf] = &q
2908 }
2909}
2910
2911//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
2912//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
2913//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05302914func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
2915 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00002916 if err != nil {
2917 log.Errorw("Failed to get the flow group from KV store", log.Fields{"groupId": groupID, "err": err})
2918 return nil, false, errors.New("failed to retrieve the flow group")
2919 }
2920 if exists {
2921 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
2922 }
2923 return nil, exists, nil
2924}
2925
2926func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
2927 groupDesc := ofp.OfpGroupDesc{
2928 Type: ofp.OfpGroupType_OFPGT_ALL,
2929 GroupId: groupID,
2930 }
2931 groupEntry := ofp.OfpGroupEntry{
2932 Desc: &groupDesc,
2933 }
2934 var acts []*ofp.OfpAction
2935 for i := 0; i < len(outPorts); i++ {
2936 acts = append(acts, flows.Output(outPorts[i]))
2937 }
2938 bucket := ofp.OfpBucket{
2939 Actions: acts,
2940 }
2941 groupDesc.Buckets = []*ofp.OfpBucket{&bucket}
2942 return &groupEntry
2943}