blob: c817455f62e94c7c6b98e2ba55414ed76d29c3f5 [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
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002009 var current *openoltpb2.Group // represents the group on the device
Esin Karamanccb714b2019-11-29 15:02:06 +00002010 if groupExists {
2011 // group already exists
2012 current = f.buildGroup(group.Desc.GroupId, val.Desc.GetBuckets())
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002013 log.Debugw("modify-group: group exists.", log.Fields{"group on the device": val, "new": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002014 } else {
2015 current = f.buildGroup(group.Desc.GroupId, nil)
2016 }
2017
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002018 log.Debugw("modify-group: comparing current and new.", log.Fields{"group on the device": current, "new": new})
2019 // get members to be added
2020 membersToBeAdded := f.findDiff(current, new)
2021 // get members to be removed
2022 membersToBeRemoved := f.findDiff(new, current)
Esin Karamanccb714b2019-11-29 15:02:06 +00002023
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002024 log.Infow("modify-group -> differences found", log.Fields{"membersToBeAdded": membersToBeAdded,
2025 "membersToBeRemoved": membersToBeRemoved, "groupId": group.Desc.GroupId})
Esin Karamanccb714b2019-11-29 15:02:06 +00002026
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002027 groupToOlt := openoltpb2.Group{
2028 GroupId: group.Desc.GroupId,
2029 }
2030 var added, removed = true, true
2031 if membersToBeAdded != nil && len(membersToBeAdded) > 0 {
2032 groupToOlt.Command = openoltpb2.Group_ADD_MEMBERS
2033 groupToOlt.Members = membersToBeAdded
2034 //execute addMembers
2035 added = f.callGroupAddRemove(&groupToOlt)
2036 }
2037 if membersToBeRemoved != nil && len(membersToBeRemoved) > 0 {
2038 groupToOlt.Command = openoltpb2.Group_REMOVE_MEMBERS
2039 groupToOlt.Members = membersToBeRemoved
2040 //execute removeMembers
2041 removed = f.callGroupAddRemove(&groupToOlt)
Esin Karamanccb714b2019-11-29 15:02:06 +00002042 }
2043
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002044 //save the modified group
2045 if added && removed {
npujarec5762e2020-01-01 14:08:48 +05302046 if err := f.resourceMgr.AddFlowGroupToKVStore(ctx, group, false); err != nil {
Esin Karamanccb714b2019-11-29 15:02:06 +00002047 log.Errorw("Failed to save the group into kv store", log.Fields{"groupId": group.Desc.GroupId})
2048 }
2049 log.Debugw("modify-group was success. Storing the group", log.Fields{"group": group, "existingGroup": current})
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002050 } else {
2051 log.Warnw("One of the group add/remove operations has failed. Cannot save group modifications",
2052 log.Fields{"group": group})
Esin Karamanccb714b2019-11-29 15:02:06 +00002053 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002054 return added && removed
Esin Karamanccb714b2019-11-29 15:02:06 +00002055}
2056
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002057//callGroupAddRemove performs add/remove buckets operation for the indicated group
2058func (f *OpenOltFlowMgr) callGroupAddRemove(group *openoltpb2.Group) bool {
2059 if err := f.performGroupOperation(group); err != nil {
2060 st, _ := status.FromError(err)
2061 //ignore already exists error code
2062 if st.Code() != codes.AlreadyExists {
2063 return false
Esin Karamanccb714b2019-11-29 15:02:06 +00002064 }
2065 }
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002066 return true
Esin Karamanccb714b2019-11-29 15:02:06 +00002067}
2068
2069//findDiff compares group members and finds members which only exists in groups2
2070func (f *OpenOltFlowMgr) findDiff(group1 *openoltpb2.Group, group2 *openoltpb2.Group) []*openoltpb2.GroupMember {
2071 var members []*openoltpb2.GroupMember
2072 for _, bucket := range group2.Members {
2073 if !f.contains(group1.Members, bucket) {
2074 // bucket does not exist and must be added
2075 members = append(members, bucket)
2076 }
2077 }
2078 return members
2079}
2080
2081//contains returns true if the members list contains the given member; false otherwise
2082func (f *OpenOltFlowMgr) contains(members []*openoltpb2.GroupMember, member *openoltpb2.GroupMember) bool {
2083 for _, groupMember := range members {
2084 if groupMember.InterfaceId == member.InterfaceId {
2085 return true
2086 }
2087 }
2088 return false
2089}
2090
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002091//performGroupOperation call performGroupOperation operation of openolt proto
2092func (f *OpenOltFlowMgr) performGroupOperation(group *openoltpb2.Group) error {
Esin Karamanccb714b2019-11-29 15:02:06 +00002093 log.Debugw("Sending group to device", log.Fields{"groupToOlt": group, "command": group.Command})
2094 _, err := f.deviceHandler.Client.PerformGroupOperation(context.Background(), group)
2095 if err != nil {
2096 log.Errorw("group operation failed", log.Fields{"err": err, "groupToOlt": group})
2097 }
2098 return err
2099}
2100
2101//buildGroup build openoltpb2.Group from given group id and bucket list
2102func (f *OpenOltFlowMgr) buildGroup(groupID uint32, buckets []*ofp.OfpBucket) *openoltpb2.Group {
2103 group := openoltpb2.Group{
2104 GroupId: groupID}
2105 // create members of the group
2106 if buckets != nil {
2107 for _, ofBucket := range buckets {
2108 member := f.buildMember(ofBucket)
2109 if member != nil && !f.contains(group.Members, member) {
2110 group.Members = append(group.Members, member)
2111 }
2112 }
2113 }
2114 return &group
2115}
2116
2117//buildMember builds openoltpb2.GroupMember from an OpenFlow bucket
2118func (f *OpenOltFlowMgr) buildMember(ofBucket *ofp.OfpBucket) *openoltpb2.GroupMember {
2119 var outPort uint32
2120 outPortFound := false
2121 for _, ofAction := range ofBucket.Actions {
2122 if ofAction.Type == ofp.OfpActionType_OFPAT_OUTPUT {
2123 outPort = ofAction.GetOutput().Port
2124 outPortFound = true
2125 }
2126 }
2127
2128 if !outPortFound {
2129 log.Debugw("bucket skipped since no out port found in it",
2130 log.Fields{"ofBucket": ofBucket})
2131 return nil
2132 }
2133 interfaceID := IntfIDFromUniPortNum(outPort)
2134 log.Debugw("got associated interface id of the port", log.Fields{"portNumber:": outPort, "interfaceId:": interfaceID})
2135 if groupInfo, ok := f.interfaceToMcastQueueMap[interfaceID]; ok {
2136 member := openoltpb2.GroupMember{
2137 InterfaceId: interfaceID,
2138 InterfaceType: openoltpb2.GroupMember_PON,
2139 GemPortId: groupInfo.gemPortID,
2140 Priority: groupInfo.servicePriority,
2141 }
2142 //add member to the group
2143 return &member
2144 }
2145 log.Warnf("bucket skipped since interface-2-gem mapping cannot be found",
2146 log.Fields{"ofBucket": ofBucket})
2147 return nil
2148}
2149
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002150//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04002151func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002152
2153 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05302154 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002155 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05302156 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05302157 }
Manikkaraj k884c1242019-04-11 16:26:42 +05302158 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04002159
Manikkaraj kb1d51442019-07-23 10:41:02 -04002160 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002161 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04002162 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
2163 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
2164 tpDownloadMsg,
2165 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
2166 f.deviceHandler.deviceType,
2167 onuDevice.Type,
2168 onuDevice.Id,
2169 onuDevice.ProxyAddress.DeviceId, "")
2170 if sendErr != nil {
2171 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
2172 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
2173 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
2174 return sendErr
2175 }
2176 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05302177 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05302178}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002179
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302180//UpdateOnuInfo function adds onu info to cache and kvstore
npujarec5762e2020-01-01 14:08:48 +05302181func (f *OpenOltFlowMgr) UpdateOnuInfo(ctx context.Context, intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302182
2183 f.lockCache.Lock()
2184 defer f.lockCache.Unlock()
2185 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
2186 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
npujarec5762e2020-01-01 14:08:48 +05302187 if err := f.resourceMgr.AddOnuInfo(ctx, intfID, onu); err != nil {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302188 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
2189 return
2190 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002191 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
2192}
2193
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302194//addGemPortToOnuInfoMap function adds GEMport to ONU map
npujarec5762e2020-01-01 14:08:48 +05302195func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(ctx context.Context, intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302196 f.lockCache.Lock()
2197 defer f.lockCache.Unlock()
2198 onugem := f.onuGemInfo[intfID]
2199 // update the gem to the local cache as well as to kv strore
2200 for idx, onu := range onugem {
2201 if onu.OnuID == onuID {
2202 // check if gem already exists , else update the cache and kvstore
2203 for _, gem := range onu.GemPorts {
2204 if gem == gemPort {
2205 log.Debugw("Gem already in cache, no need to update cache and kv store",
2206 log.Fields{"gem": gemPort})
2207 return
2208 }
2209 }
2210 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
2211 f.onuGemInfo[intfID] = onugem
2212 }
2213 }
npujarec5762e2020-01-01 14:08:48 +05302214 err := f.resourceMgr.AddGemToOnuGemInfo(ctx, intfID, onuID, gemPort)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302215 if err != nil {
2216 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002217 return
2218 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002219}
2220
2221// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002222
2223//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
2224func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302225
2226 f.lockCache.Lock()
2227 defer f.lockCache.Unlock()
2228
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002229 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 +05302230 // get onuid from the onugem info cache
2231 onugem := f.onuGemInfo[intfID]
2232 for _, onu := range onugem {
2233 for _, gem := range onu.GemPorts {
2234 if gem == gemPortID {
2235 return onu.OnuID, nil
2236 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002237 }
2238 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002239 log.Errorw("onuid is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPort": gemPortID})
2240 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 -04002241}
2242
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002243//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
npujarec5762e2020-01-01 14:08:48 +05302244func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(ctx context.Context, packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002245 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002246 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002247 var err error
2248
2249 if packetIn.IntfType == "pon" {
2250 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002251 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002252 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
2253 return logicalPortNum, err
2254 }
2255 if packetIn.PortNo != 0 {
2256 logicalPortNum = packetIn.PortNo
2257 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002258 uniID := uint32(0) // FIXME - multi-uni support
2259 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002260 }
2261 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
npujarec5762e2020-01-01 14:08:48 +05302262 f.UpdateGemPortForPktIn(ctx, packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002263 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002264 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002265 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08002266 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
2267 "logicalPortNum": logicalPortNum,
2268 "IntfType": packetIn.IntfType,
2269 "packet": hex.EncodeToString(packetIn.Pkt),
2270 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002271 return logicalPortNum, nil
2272}
2273
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002274//GetPacketOutGemPortID returns gemPortId
npujarec5762e2020-01-01 14:08:48 +05302275func (f *OpenOltFlowMgr) GetPacketOutGemPortID(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002276 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002277 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302278
2279 f.lockCache.Lock()
2280 defer f.lockCache.Unlock()
2281 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
2282
2283 gemPortID, ok := f.packetInGemPort[pktInkey]
2284 if ok {
2285 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2286 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002287 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302288 //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 +05302289 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302290 if err == nil {
2291 if gemPortID != 0 {
2292 f.packetInGemPort[pktInkey] = gemPortID
2293 log.Debugw("Found gem port from kv store and updating cache with gemport",
2294 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2295 return gemPortID, nil
2296 }
2297 }
2298 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
2299 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002300}
2301
npujarec5762e2020-01-01 14:08:48 +05302302func installFlowOnAllGemports(ctx context.Context,
2303 f1 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32,
Manikkaraj kb1d51442019-07-23 10:41:02 -04002304 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
2305 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32),
npujarec5762e2020-01-01 14:08:48 +05302306 f2 func(ctx context.Context, intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302307 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
2308 classifier map[string]interface{}, action map[string]interface{}),
Manikkaraj kb1d51442019-07-23 10:41:02 -04002309 args map[string]uint32,
2310 classifier map[string]interface{}, action map[string]interface{},
2311 logicalFlow *ofp.OfpFlowStats,
2312 gemPorts []uint32,
2313 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002314 vlanID ...uint32) {
2315 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
2316 for _, gemPortID := range gemPorts {
Manikkaraj kb1d51442019-07-23 10:41:02 -04002317 if FlowType == HsiaFlow || FlowType == DhcpFlow {
npujarec5762e2020-01-01 14:08:48 +05302318 f1(ctx, args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04002319 } else if FlowType == EapolFlow {
npujarec5762e2020-01-01 14:08:48 +05302320 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 -04002321 } else {
2322 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
2323 return
2324 }
2325 }
2326}
2327
npujarec5762e2020-01-01 14:08:48 +05302328func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002329 log.Debug("Adding trap-dhcp-of-nni-flow")
2330 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002331 classifier[PacketTagType] = DoubleTag
2332 action[TrapToHost] = true
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302333 var err error
2334 var networkInterfaceID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002335 /* We manage flowId resource pool on per PON port basis.
2336 Since this situation is tricky, as a hack, we pass the NNI port
2337 index (network_intf_id) as PON port Index for the flowId resource
2338 pool. Also, there is no ONU Id available for trapping DHCP packets
2339 on NNI port, use onu_id as -1 (invalid)
2340 ****************** CAVEAT *******************
2341 This logic works if the NNI Port Id falls within the same valid
2342 range of PON Port Ids. If this doesn't work for some OLT Vendor
2343 we need to have a re-look at this.
2344 *********************************************
2345 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002346 onuID := -1
2347 uniID := -1
2348 gemPortID := -1
2349 allocID := -1
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302350 networkInterfaceID, err = getNniIntfID(classifier, action)
2351 if err != nil {
2352 log.Error("Failed to get nniIntf ID")
2353 return
2354 }
2355
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002356 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302357 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002358 log.Debug("Flow-exists--not-re-adding")
2359 return
2360 }
npujarec5762e2020-01-01 14:08:48 +05302361 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002362 if err != nil {
2363 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
2364 return
2365 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002366 var classifierProto *openoltpb2.Classifier
2367 var actionProto *openoltpb2.Action
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002368 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
2369 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
2370 return
2371 }
2372 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
2373 if actionProto = makeOpenOltActionField(action); actionProto == nil {
2374 log.Error("Error in making action protobuf for dhcp trap on nni flow")
2375 return
2376 }
2377 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002378 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2379 OnuId: int32(onuID), // OnuId not required
2380 UniId: int32(uniID), // UniId not used
2381 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07002382 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002383 AllocId: int32(allocID), // AllocId not used
2384 NetworkIntfId: int32(networkInterfaceID),
2385 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002386 Classifier: classifierProto,
2387 Action: actionProto,
2388 Priority: int32(logicalFlow.Priority),
2389 Cookie: logicalFlow.Cookie,
2390 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +05302391 if ok := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002392 log.Debug("DHCP trap on NNI flow added to device successfully")
npujarec5762e2020-01-01 14:08:48 +05302393 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2394 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07002395 int32(onuID),
2396 int32(uniID),
2397 flowID, flowsToKVStore); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04002398 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
2399 }
2400 }
2401 return
2402}
salmansiddiqui7ac62132019-08-22 03:58:50 +00002403
Esin Karamanae41e2b2019-12-17 18:13:13 +00002404//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
2405func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
2406 var packetType string
2407 ovid, ivid := false, false
2408 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
2409 vid := vlanID & VlanvIDMask
2410 if vid != ReservedVlan {
2411 ovid = true
2412 }
2413 }
2414 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
2415 vid := uint32(metadata)
2416 if vid != ReservedVlan {
2417 ivid = true
2418 }
2419 }
2420 if ovid && ivid {
2421 packetType = DoubleTag
2422 } else if !ovid && !ivid {
2423 packetType = Untagged
2424 } else {
2425 packetType = SingleTag
2426 }
2427 return packetType
2428}
2429
2430//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
npujarec5762e2020-01-01 14:08:48 +05302431func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(ctx context.Context, logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002432 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2433 action := make(map[string]interface{})
2434 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2435 action[TrapToHost] = true
2436 /* We manage flowId resource pool on per PON port basis.
2437 Since this situation is tricky, as a hack, we pass the NNI port
2438 index (network_intf_id) as PON port Index for the flowId resource
2439 pool. Also, there is no ONU Id available for trapping packets
2440 on NNI port, use onu_id as -1 (invalid)
2441 ****************** CAVEAT *******************
2442 This logic works if the NNI Port Id falls within the same valid
2443 range of PON Port Ids. If this doesn't work for some OLT Vendor
2444 we need to have a re-look at this.
2445 *********************************************
2446 */
2447 onuID := -1
2448 uniID := -1
2449 gemPortID := -1
2450 allocID := -1
2451 networkInterfaceID, err := getNniIntfID(classifier, action)
2452 if err != nil {
2453 log.Error("Failed to get nniIntf ID")
2454 return
2455 }
2456 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
npujarec5762e2020-01-01 14:08:48 +05302457 if present := f.resourceMgr.IsFlowCookieOnKVStore(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002458 log.Debug("igmp-flow-exists--not-re-adding")
2459 return
2460 }
npujarec5762e2020-01-01 14:08:48 +05302461 flowID, err := f.resourceMgr.GetFlowID(ctx, uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002462 if err != nil {
2463 log.Errorw("IGMP flow id unavailable for trap-on-NNI flow", log.Fields{"error": err})
2464 return
2465 }
2466 var classifierProto *openoltpb2.Classifier
2467 var actionProto *openoltpb2.Action
2468 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
2469 log.Error("Error in making classifier protobuf for igmp trap on nni flow")
2470 return
2471 }
2472 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
2473 if actionProto = makeOpenOltActionField(action); actionProto == nil {
2474 log.Error("Error in making action protobuf for IGMP trap on nni flow")
2475 return
2476 }
2477 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2478 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2479 OnuId: int32(onuID), // OnuId not required
2480 UniId: int32(uniID), // UniId not used
2481 FlowId: flowID,
2482 FlowType: Downstream,
2483 AllocId: int32(allocID), // AllocId not used
2484 NetworkIntfId: int32(networkInterfaceID),
2485 GemportId: int32(gemPortID), // GemportId not used
2486 Classifier: classifierProto,
2487 Action: actionProto,
2488 Priority: int32(logicalFlow.Priority),
2489 Cookie: logicalFlow.Cookie,
2490 PortNo: portNo}
npujarec5762e2020-01-01 14:08:48 +05302491 if ok := f.addFlowToDevice(ctx, logicalFlow, &downstreamflow); ok {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002492 log.Debug("IGMP Trap on NNI flow added to device successfully")
npujarec5762e2020-01-01 14:08:48 +05302493 flowsToKVStore := f.getUpdatedFlowInfo(ctx, &downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2494 if err := f.updateFlowInfoToKVStore(ctx, int32(networkInterfaceID),
Esin Karamanae41e2b2019-12-17 18:13:13 +00002495 int32(onuID),
2496 int32(uniID),
2497 flowID, flowsToKVStore); err != nil {
2498 log.Errorw("Error uploading igmp-trap-on-nni flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
2499 }
2500 }
2501 return
2502}
2503
salmansiddiqui7ac62132019-08-22 03:58:50 +00002504func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2505 if MeterID == 0 { // This should never happen
2506 log.Error("Invalid meter id")
2507 return "", errors.New("invalid meter id")
2508 }
2509 if Dir == tp_pb.Direction_UPSTREAM {
2510 return "upstream", nil
2511 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2512 return "downstream", nil
2513 }
2514 return "", nil
2515}
2516
npujarec5762e2020-01-01 14:08:48 +05302517func (f *OpenOltFlowMgr) checkAndAddFlow(ctx context.Context, args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002518 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2519 TpID uint32, uni string) {
2520 var gemPort uint32
2521 intfID := args[IntfID]
2522 onuID := args[OnuID]
2523 uniID := args[UniID]
2524 portNo := args[PortNo]
2525 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002526 if ipProto, ok := classifierInfo[IPProto]; ok {
2527 if ipProto.(uint32) == IPProtoDhcp {
2528 log.Info("Adding DHCP flow")
2529 if pcp, ok := classifierInfo[VlanPcp]; ok {
2530 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2531 tp_pb.Direction_UPSTREAM,
2532 pcp.(uint32))
2533 //Adding DHCP upstream flow
npujarec5762e2020-01-01 14:08:48 +05302534 f.addDHCPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002535 } else {
2536 //Adding DHCP upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302537 installFlowOnAllGemports(ctx, f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002538 }
2539
2540 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002541 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2542 if pcp, ok := classifierInfo[VlanPcp]; ok {
2543 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2544 tp_pb.Direction_UPSTREAM,
2545 pcp.(uint32))
npujarec5762e2020-01-01 14:08:48 +05302546 f.addIGMPTrapFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002547 } else {
2548 //Adding IGMP upstream flow to all gem ports
npujarec5762e2020-01-01 14:08:48 +05302549 installFlowOnAllGemports(ctx, f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, IgmpFlow)
Esin Karamanae41e2b2019-12-17 18:13:13 +00002550 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002551 } else {
2552 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2553 return
2554 }
2555 } else if ethType, ok := classifierInfo[EthType]; ok {
2556 if ethType.(uint32) == EapEthType {
2557 log.Info("Adding EAPOL flow")
2558 var vlanID uint32
2559 if val, ok := classifierInfo[VlanVid]; ok {
2560 vlanID = (val.(uint32)) & VlanvIDMask
2561 } else {
2562 vlanID = DefaultMgmtVlan
2563 }
2564 if pcp, ok := classifierInfo[VlanPcp]; ok {
2565 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2566 tp_pb.Direction_UPSTREAM,
2567 pcp.(uint32))
2568
npujarec5762e2020-01-01 14:08:48 +05302569 f.addEAPOLFlow(ctx, intfID, onuID, uniID, portNo, flow, allocID, gemPort, vlanID, classifierInfo, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002570 } else {
npujarec5762e2020-01-01 14:08:48 +05302571 installFlowOnAllGemports(ctx, nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002572 }
2573 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002574 } else if _, ok := actionInfo[PushVlan]; ok {
2575 log.Info("Adding upstream data rule")
2576 if pcp, ok := classifierInfo[VlanPcp]; ok {
2577 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2578 tp_pb.Direction_UPSTREAM,
2579 pcp.(uint32))
2580 //Adding HSIA upstream flow
npujarec5762e2020-01-01 14:08:48 +05302581 f.addUpstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002582 } else {
2583 //Adding HSIA upstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302584 installFlowOnAllGemports(ctx, f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002585 }
2586 } else if _, ok := actionInfo[PopVlan]; ok {
2587 log.Info("Adding Downstream data rule")
2588 if pcp, ok := classifierInfo[VlanPcp]; ok {
2589 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002590 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002591 pcp.(uint32))
2592 //Adding HSIA downstream flow
npujarec5762e2020-01-01 14:08:48 +05302593 f.addDownstreamDataFlow(ctx, intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002594 } else {
2595 //Adding HSIA downstream flow to all gemports
npujarec5762e2020-01-01 14:08:48 +05302596 installFlowOnAllGemports(ctx, f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002597 }
2598 } else {
2599 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2600 return
2601 }
2602 // Send Techprofile download event to child device in go routine as it takes time
2603 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2604}
2605
Gamze Abakafee36392019-10-03 11:17:24 +00002606func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2607 flowIDList := f.flowsUsedByGemPort[gemPK]
2608 if len(flowIDList) > 1 {
2609 return true
2610 }
2611 return false
2612}
2613
npujarec5762e2020-01-01 14:08:48 +05302614func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ctx context.Context, ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
2615 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ctx, ponIntf, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00002616 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2617 for _, currentGemPort := range currentGemPorts {
2618 for _, tpGemPort := range tpGemPorts {
2619 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2620 return true, currentGemPort
2621 }
2622 }
2623 }
Girish Gowdra54934262019-11-13 14:19:55 +05302624 if tpInst.InstanceCtrl.Onu == "single-instance" {
2625 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
npujarec5762e2020-01-01 14:08:48 +05302626 f.resourceMgr.RemoveTechProfileIDForOnu(ctx, ponIntf, uint32(onuID), uint32(uniID), tpID)
2627 f.DeleteTechProfileInstance(ctx, ponIntf, uint32(onuID), uint32(uniID), "", tpID)
Girish Gowdra54934262019-11-13 14:19:55 +05302628
2629 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2630 // still be used on other uni ports.
2631 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2632 // on any other uni port.
npujarec5762e2020-01-01 14:08:48 +05302633 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(ctx, tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302634 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302635 for i := 0; i < len(tpInstances); i++ {
2636 tpI := tpInstances[i]
2637 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302638 for _, tpGemPort := range tpGemPorts {
2639 if tpGemPort.GemportID != gemPortID {
2640 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2641 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302642 }
2643 }
2644 }
2645 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302646 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002647 return false, 0
2648}
2649
salmansiddiqui7ac62132019-08-22 03:58:50 +00002650func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002651 for _, field := range flows.GetOfbFields(flow) {
2652 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002653 classifierInfo[EthType] = field.GetEthType()
2654 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Esin Karamanccb714b2019-11-29 15:02:06 +00002655 } else if field.Type == flows.ETH_DST {
2656 classifierInfo[EthDst] = field.GetEthDst()
2657 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_DST]": classifierInfo[EthDst].([]uint8)})
Scott Baker355d1742019-10-24 10:57:52 -07002658 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002659 classifierInfo[IPProto] = field.GetIpProto()
2660 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002661 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002662 classifierInfo[InPort] = field.GetPort()
2663 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002664 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302665 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002666 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002667 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002668 classifierInfo[VlanPcp] = field.GetVlanPcp()
2669 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002670 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002671 classifierInfo[UDPDst] = field.GetUdpDst()
2672 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002673 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002674 classifierInfo[UDPSrc] = field.GetUdpSrc()
2675 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002676 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002677 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2678 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002679 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002680 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2681 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002682 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002683 classifierInfo[Metadata] = field.GetTableMetadata()
2684 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002685 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002686 classifierInfo[TunnelID] = field.GetTunnelId()
2687 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2688 } else {
2689 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2690 return
2691 }
2692 }
2693}
2694
2695func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002696 for _, action := range flows.GetActions(flow) {
2697 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002698 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002699 actionInfo[Output] = out.GetPort()
2700 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002701 } else {
2702 log.Error("Invalid output port in action")
2703 return errors.New("invalid output port in action")
2704 }
Scott Baker355d1742019-10-24 10:57:52 -07002705 } else if action.Type == flows.POP_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002706 actionInfo[PopVlan] = true
2707 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002708 } else if action.Type == flows.PUSH_VLAN {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002709 if out := action.GetPush(); out != nil {
2710 if tpid := out.GetEthertype(); tpid != 0x8100 {
2711 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
2712 } else {
2713 actionInfo[PushVlan] = true
2714 actionInfo[TPID] = tpid
2715 log.Debugw("action-type-push-vlan",
2716 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
2717 }
2718 }
Scott Baker355d1742019-10-24 10:57:52 -07002719 } else if action.Type == flows.SET_FIELD {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002720 if out := action.GetSetField(); out != nil {
2721 if field := out.GetField(); field != nil {
2722 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
2723 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
2724 return errors.New("invalid openflow class")
2725 }
2726 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
Esin Karamanccb714b2019-11-29 15:02:06 +00002727 formulateSetFieldActionInfoFromFlow(field, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002728 }
2729 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002730 } else if action.Type == flows.GROUP {
2731 formulateGroupActionInfoFromFlow(action, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002732 } else {
2733 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
2734 return errors.New("un supported action type")
2735 }
2736 }
2737 return nil
2738}
2739
Esin Karamanccb714b2019-11-29 15:02:06 +00002740func formulateSetFieldActionInfoFromFlow(field *ofp.OfpOxmField, actionInfo map[string]interface{}) {
2741 if ofbField := field.GetOfbField(); ofbField != nil {
2742 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
2743 if vlan := ofbField.GetVlanVid(); vlan != 0 {
2744 actionInfo[VlanVid] = vlan & 0xfff
2745 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
2746 } else {
2747 log.Error("No Invalid vlan id in set vlan-vid action")
2748 }
2749 } else {
2750 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
2751 }
2752 }
2753}
2754
2755func formulateGroupActionInfoFromFlow(action *ofp.OfpAction, actionInfo map[string]interface{}) {
2756 if action.GetGroup() == nil {
2757 log.Warn("No group entry found in the group action")
2758 } else {
2759 actionInfo[GroupID] = action.GetGroup().GroupId
2760 log.Debugw("action-group-id", log.Fields{"actionInfo[GroupID]": actionInfo[GroupID].(uint32)})
2761 }
2762}
2763
salmansiddiqui7ac62132019-08-22 03:58:50 +00002764func formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002765 if isControllerFlow := IsControllerBoundFlow(actionInfo[Output].(uint32)); isControllerFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002766 log.Debug("Controller bound trap flows, getting inport from tunnelid")
2767 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
2768 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002769 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002770 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002771 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 +00002772 } else {
2773 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
2774 return errors.New("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
2775 }
2776 }
2777 } else {
2778 log.Debug("Non-Controller flows, getting uniport from tunnelid")
2779 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
David K. Bainbridge82efc492019-09-04 09:57:11 -07002780 if portType := IntfIDToPortTypeName(actionInfo[Output].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002781 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002782 actionInfo[Output] = uniPort
2783 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 +00002784 } else {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002785 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 +00002786 return errors.New("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid")
2787 }
2788 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
2789 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Scott Baker355d1742019-10-24 10:57:52 -07002790 if uniPort := flows.GetChildPortFromTunnelId(flow); uniPort != 0 {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002791 classifierInfo[InPort] = uniPort
David K. Bainbridge82efc492019-09-04 09:57:11 -07002792 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[Output].(uint32),
2793 "outport": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002794 } else {
2795 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 -07002796 "outPort": actionInfo[Output].(uint32)})
salmansiddiqui7ac62132019-08-22 03:58:50 +00002797 return errors.New("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid")
2798 }
2799 }
2800 }
2801 return nil
2802}
Gamze Abakafee36392019-10-03 11:17:24 +00002803
Chaitrashree G S90a17952019-11-14 21:51:21 -05002804func getTpIDFromFlow(flow *ofp.OfpFlowStats) (uint32, error) {
Gamze Abakafee36392019-10-03 11:17:24 +00002805 /* Metadata 8 bytes:
2806 Most Significant 2 Bytes = Inner VLAN
2807 Next 2 Bytes = Tech Profile ID(TPID)
2808 Least Significant 4 Bytes = Port ID
2809 Flow Metadata carries Tech-Profile (TP) ID and is mandatory in all
2810 subscriber related flows.
2811 */
2812 metadata := flows.GetMetadataFromWriteMetadataAction(flow)
2813 if metadata == 0 {
Chaitrashree G S90a17952019-11-14 21:51:21 -05002814 log.Error("metadata-is-not-present-in-flow-which-is-mandatory")
2815 return 0, errors.New("metadata-is-not-present-in-flow-which-is-mandatory")
Gamze Abakafee36392019-10-03 11:17:24 +00002816 }
2817 TpID := flows.GetTechProfileIDFromWriteMetaData(metadata)
Chaitrashree G S90a17952019-11-14 21:51:21 -05002818 return uint32(TpID), nil
Gamze Abakafee36392019-10-03 11:17:24 +00002819}
2820
2821func appendUnique(slice []uint32, item uint32) []uint32 {
2822 for _, sliceElement := range slice {
2823 if sliceElement == item {
2824 return slice
2825 }
2826 }
2827 return append(slice, item)
2828}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302829
2830// getNniIntfID gets nni intf id from the flow classifier/action
2831func getNniIntfID(classifier map[string]interface{}, action map[string]interface{}) (uint32, error) {
2832
2833 portType := IntfIDToPortTypeName(classifier[InPort].(uint32))
2834 if portType == voltha.Port_PON_OLT {
2835 intfID := IntfIDFromNniPortNum(action[Output].(uint32))
2836 log.Debugw("output Nni IntfID is", log.Fields{"intfid": intfID})
2837 return intfID, nil
2838 } else if portType == voltha.Port_ETHERNET_NNI {
2839 intfID := IntfIDFromNniPortNum(classifier[InPort].(uint32))
2840 log.Debugw("input Nni IntfID is", log.Fields{"intfid": intfID})
2841 return intfID, nil
2842 }
2843 return uint32(0), nil
2844}
2845
2846// UpdateGemPortForPktIn updates gemport for packet-in in to the cache and to the kv store as well.
npujarec5762e2020-01-01 14:08:48 +05302847func (f *OpenOltFlowMgr) UpdateGemPortForPktIn(ctx context.Context, intfID uint32, onuID uint32, logicalPort uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302848 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: logicalPort}
2849
2850 f.lockCache.Lock()
2851 defer f.lockCache.Unlock()
Matt Jeanneret1719a072019-12-20 14:50:14 -05002852 lookupGemPort, ok := f.packetInGemPort[pktInkey]
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302853 if ok {
Matt Jeanneret1719a072019-12-20 14:50:14 -05002854 if lookupGemPort == gemPort {
2855 log.Debugw("pktin key/value found in cache , no need to update kv as we are assuming both will be in sync",
2856 log.Fields{"pktinkey": pktInkey, "gem": gemPort})
2857 return
2858 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302859 }
Matt Jeanneret1719a072019-12-20 14:50:14 -05002860 f.packetInGemPort[pktInkey] = gemPort
2861
npujarec5762e2020-01-01 14:08:48 +05302862 f.resourceMgr.UpdateGemPortForPktIn(ctx, pktInkey, gemPort)
Matt Jeanneret1719a072019-12-20 14:50:14 -05002863 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 +05302864 return
2865}
2866
2867// AddUniPortToOnuInfo adds uni port to the onugem info both in cache and kvstore.
npujarec5762e2020-01-01 14:08:48 +05302868func (f *OpenOltFlowMgr) AddUniPortToOnuInfo(ctx context.Context, intfID uint32, onuID uint32, portNum uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302869
2870 f.lockCache.Lock()
2871 defer f.lockCache.Unlock()
2872 onugem := f.onuGemInfo[intfID]
2873 for idx, onu := range onugem {
2874 if onu.OnuID == onuID {
2875 for _, uni := range onu.UniPorts {
2876 if uni == portNum {
2877 log.Debugw("uni already in cache, no need to update cache and kv store",
2878 log.Fields{"uni": portNum})
2879 return
2880 }
2881 }
2882 onugem[idx].UniPorts = append(onugem[idx].UniPorts, portNum)
2883 f.onuGemInfo[intfID] = onugem
2884 }
2885 }
npujarec5762e2020-01-01 14:08:48 +05302886 f.resourceMgr.AddUniPortToOnuInfo(ctx, intfID, onuID, portNum)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302887}
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302888
npujarec5762e2020-01-01 14:08:48 +05302889func (f *OpenOltFlowMgr) loadFlowIDlistForGem(ctx context.Context, intf uint32) {
2890 flowIDsList, err := f.resourceMgr.GetFlowIDsGemMapForInterface(ctx, intf)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05302891 if err != nil {
2892 log.Error("Failed to get flowid list per gem", log.Fields{"intf": intf})
2893 return
2894 }
2895 for gem, FlowIDs := range flowIDsList {
2896 gemPK := gemPortKey{intf, uint32(gem)}
2897 f.flowsUsedByGemPort[gemPK] = FlowIDs
2898 }
2899 return
2900}
Esin Karamanccb714b2019-11-29 15:02:06 +00002901
2902//loadInterfaceToMulticastQueueMap reads multicast queues per interface from the KV store
2903//and put them into interfaceToMcastQueueMap.
npujarec5762e2020-01-01 14:08:48 +05302904func (f *OpenOltFlowMgr) loadInterfaceToMulticastQueueMap(ctx context.Context) {
2905 storedMulticastQueueMap, err := f.resourceMgr.GetMcastQueuePerInterfaceMap(ctx)
Esin Karamanccb714b2019-11-29 15:02:06 +00002906 if err != nil {
2907 log.Error("Failed to get pon interface to multicast queue map")
2908 return
2909 }
2910 for intf, queueInfo := range storedMulticastQueueMap {
2911 q := queueInfoBrief{
2912 gemPortID: queueInfo[0],
2913 servicePriority: queueInfo[1],
2914 }
2915 f.interfaceToMcastQueueMap[intf] = &q
2916 }
2917}
2918
2919//GetFlowGroupFromKVStore fetches and returns flow group from the KV store. Returns (nil, false, error) if any problem occurs during
2920//fetching the data. Returns (group, true, nil) if the group is fetched and returned successfully.
2921//Returns (nil, false, nil) if the group does not exists in the KV store.
npujarec5762e2020-01-01 14:08:48 +05302922func (f *OpenOltFlowMgr) GetFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) (*ofp.OfpGroupEntry, bool, error) {
2923 exists, groupInfo, err := f.resourceMgr.GetFlowGroupFromKVStore(ctx, groupID, cached)
Esin Karamanccb714b2019-11-29 15:02:06 +00002924 if err != nil {
2925 log.Errorw("Failed to get the flow group from KV store", log.Fields{"groupId": groupID, "err": err})
2926 return nil, false, errors.New("failed to retrieve the flow group")
2927 }
2928 if exists {
2929 return newGroup(groupInfo.GroupID, groupInfo.OutPorts), exists, nil
2930 }
2931 return nil, exists, nil
2932}
2933
2934func newGroup(groupID uint32, outPorts []uint32) *ofp.OfpGroupEntry {
2935 groupDesc := ofp.OfpGroupDesc{
2936 Type: ofp.OfpGroupType_OFPGT_ALL,
2937 GroupId: groupID,
2938 }
2939 groupEntry := ofp.OfpGroupEntry{
2940 Desc: &groupDesc,
2941 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002942 for i := 0; i < len(outPorts); i++ {
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002943 var acts []*ofp.OfpAction
Esin Karamanccb714b2019-11-29 15:02:06 +00002944 acts = append(acts, flows.Output(outPorts[i]))
Esin Karaman0ebd2a32020-02-09 18:45:36 +00002945 bucket := ofp.OfpBucket{
2946 Actions: acts,
2947 }
2948 groupDesc.Buckets = append(groupDesc.Buckets, &bucket)
Esin Karamanccb714b2019-11-29 15:02:06 +00002949 }
Esin Karamanccb714b2019-11-29 15:02:06 +00002950 return &groupEntry
2951}