blob: cb746c2de6ea372c95932ac2ef965606a23eef53 [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
Scott Baker51290152019-10-24 14:23:20 -070031 "github.com/opencord/voltha-lib-go/v2/pkg/flows"
32 "github.com/opencord/voltha-lib-go/v2/pkg/log"
33 tp "github.com/opencord/voltha-lib-go/v2/pkg/techprofile"
Manikkaraj k884c1242019-04-11 16:26:42 +053034 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
Scott Bakerc6e54cb2019-11-04 09:31:25 -080035 "github.com/opencord/voltha-protos/v2/go/common"
36 ic "github.com/opencord/voltha-protos/v2/go/inter_container"
37 ofp "github.com/opencord/voltha-protos/v2/go/openflow_13"
38 openoltpb2 "github.com/opencord/voltha-protos/v2/go/openolt"
39 tp_pb "github.com/opencord/voltha-protos/v2/go/tech_profile"
40 "github.com/opencord/voltha-protos/v2/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 Karamanae41e2b2019-12-17 18:13:13 +000060 //IgmpFlow flow category
61 IgmpFlow = "IGMP_FLOW"
62
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070063 //IPProtoDhcp flow category
64 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053065
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070066 //IPProtoIgmp flow category
67 IPProtoIgmp = 2
68
69 //EapEthType eapethtype value
70 EapEthType = 0x888e
71 //LldpEthType lldp ethtype value
72 LldpEthType = 0x88cc
Esin Karamanae41e2b2019-12-17 18:13:13 +000073 //IPv4EthType IPv4 ethernet type value
74 IPv4EthType = 0x800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070075
76 //IgmpProto proto value
77 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053078
79 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070080
Humera Kouser94d7a842019-08-25 19:04:32 -040081 //ReservedVlan Transparent Vlan
David K. Bainbridge82efc492019-09-04 09:57:11 -070082 ReservedVlan = 4095
Harsh Awasthiea45af72019-08-26 02:39:00 -040083
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070084 //DefaultMgmtVlan default vlan value
85 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053086
manikkaraj kbf256be2019-03-25 00:13:48 +053087 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070088
David K. Bainbridge82efc492019-09-04 09:57:11 -070089 //Upstream constant
90 Upstream = "upstream"
91 //Downstream constant
92 Downstream = "downstream"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070093 //PacketTagType constant
94 PacketTagType = "pkt_tag_type"
David K. Bainbridge82efc492019-09-04 09:57:11 -070095 //Untagged constant
96 Untagged = "untagged"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070097 //SingleTag constant
98 SingleTag = "single_tag"
99 //DoubleTag constant
100 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +0530101
102 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700103
104 //EthType constant
105 EthType = "eth_type"
106 //TPID constant
107 TPID = "tpid"
108 //IPProto constant
109 IPProto = "ip_proto"
110 //InPort constant
111 InPort = "in_port"
112 //VlanVid constant
113 VlanVid = "vlan_vid"
114 //VlanPcp constant
115 VlanPcp = "vlan_pcp"
116
117 //UDPDst constant
118 UDPDst = "udp_dst"
119 //UDPSrc constant
120 UDPSrc = "udp_src"
121 //Ipv4Dst constant
122 Ipv4Dst = "ipv4_dst"
123 //Ipv4Src constant
124 Ipv4Src = "ipv4_src"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700125 //Metadata constant
126 Metadata = "metadata"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700127 //TunnelID constant
128 TunnelID = "tunnel_id"
David K. Bainbridge82efc492019-09-04 09:57:11 -0700129 //Output constant
130 Output = "output"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700131 // Actions
132
133 //PopVlan constant
134 PopVlan = "pop_vlan"
135 //PushVlan constant
136 PushVlan = "push_vlan"
137 //TrapToHost constant
138 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400139 //MaxMeterBand constant
140 MaxMeterBand = 2
141 //VlanPCPMask contant
142 VlanPCPMask = 0xFF
143 //VlanvIDMask constant
144 VlanvIDMask = 0xFFF
Gamze Abakafee36392019-10-03 11:17:24 +0000145 //IntfID constant
146 IntfID = "intfId"
147 //OnuID constant
148 OnuID = "onuId"
149 //UniID constant
150 UniID = "uniId"
151 //PortNo constant
152 PortNo = "portNo"
153 //AllocID constant
154 AllocID = "allocId"
manikkaraj kbf256be2019-03-25 00:13:48 +0530155)
156
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400157type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700158 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400159 gemPort uint32
160}
161
Girish Gowdra3d633032019-12-10 16:37:05 +0530162type pendingFlowDeleteKey struct {
163 intfID uint32
164 onuID uint32
165 uniID uint32
166}
167
168type tpLockKey struct {
169 intfID uint32
170 onuID uint32
171 uniID uint32
172}
173
Gamze Abakafee36392019-10-03 11:17:24 +0000174type schedQueue struct {
175 direction tp_pb.Direction
176 intfID uint32
177 onuID uint32
178 uniID uint32
179 tpID uint32
180 uniPort uint32
181 tpInst *tp.TechProfile
182 meterID uint32
183 flowMetadata *voltha.FlowMetadata
184}
185
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700186//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530187type OpenOltFlowMgr struct {
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000188 techprofile map[uint32]tp.TechProfileIf
Gamze Abakafee36392019-10-03 11:17:24 +0000189 deviceHandler *DeviceHandler
190 resourceMgr *rsrcMgr.OpenOltResourceMgr
Gamze Abakafee36392019-10-03 11:17:24 +0000191 onuIdsLock sync.RWMutex
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530192 flowsUsedByGemPort map[gemPortKey][]uint32 //gem port id to flow ids
193 packetInGemPort map[rsrcMgr.PacketInInfoKey]uint32 //packet in gem port local cache
194 onuGemInfo map[uint32][]rsrcMgr.OnuGemInfo //onu, gem and uni info local cache
195 lockCache sync.RWMutex
Girish Gowdra3d633032019-12-10 16:37:05 +0530196 pendingFlowDelete sync.Map
197 // The mapmutex.Mutex can be fine tuned to use mapmutex.NewCustomizedMapMutex
198 perUserFlowHandleLock *mapmutex.Mutex
manikkaraj kbf256be2019-03-25 00:13:48 +0530199}
200
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700201//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530202func NewFlowManager(dh *DeviceHandler, rMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
manikkaraj kbf256be2019-03-25 00:13:48 +0530203 log.Info("Initializing flow manager")
204 var flowMgr OpenOltFlowMgr
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530205 var err error
206 var idx uint32
207
manikkaraj kbf256be2019-03-25 00:13:48 +0530208 flowMgr.deviceHandler = dh
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530209 flowMgr.resourceMgr = rMgr
Amit Ghoshd4cbe482019-11-21 12:07:14 +0000210 flowMgr.techprofile = make(map[uint32]tp.TechProfileIf)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530211 if err = flowMgr.populateTechProfilePerPonPort(); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530212 log.Error("Error while populating tech profile mgr\n")
213 return nil
214 }
William Kurkian740a09c2019-10-23 17:07:38 -0400215 flowMgr.onuIdsLock = sync.RWMutex{}
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530216 flowMgr.flowsUsedByGemPort = make(map[gemPortKey][]uint32)
217 flowMgr.packetInGemPort = make(map[rsrcMgr.PacketInInfoKey]uint32)
218 flowMgr.onuGemInfo = make(map[uint32][]rsrcMgr.OnuGemInfo)
219 ponPorts := rMgr.DevInfo.GetPonPorts()
220 //Load the onugem info cache from kv store on flowmanager start
221 for idx = 0; idx < ponPorts; idx++ {
222 if flowMgr.onuGemInfo[idx], err = rMgr.GetOnuGemInfo(idx); err != nil {
223 log.Error("Failed to load onu gem info cache")
224 }
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530225 //Load flowID list per gem map per interface from the kvstore.
226 flowMgr.loadFlowIDlistForGem(idx)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530227 }
228 flowMgr.lockCache = sync.RWMutex{}
Girish Gowdra3d633032019-12-10 16:37:05 +0530229 flowMgr.pendingFlowDelete = sync.Map{}
230 flowMgr.perUserFlowHandleLock = mapmutex.NewMapMutex()
manikkaraj kbf256be2019-03-25 00:13:48 +0530231 log.Info("Initialization of flow manager success!!")
232 return &flowMgr
233}
234
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700235func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700236 if direction == Upstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400237 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700238 return 0x1<<15 | uint64(flowID), nil
David K. Bainbridge82efc492019-09-04 09:57:11 -0700239 } else if direction == Downstream {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400240 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700241 return uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400242 } else {
243 log.Debug("Unrecognized direction")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700244 return 0, fmt.Errorf("unrecognized direction %s", direction)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400245 }
246}
247
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700248func (f *OpenOltFlowMgr) registerFlow(flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400249 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700250 log.Fields{"device": f.deviceHandler.deviceID})
Gamze Abakafee36392019-10-03 11:17:24 +0000251 gemPK := gemPortKey{uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId)}
252 flowIDList, ok := f.flowsUsedByGemPort[gemPK]
253 if !ok {
254 flowIDList = []uint32{deviceFlow.FlowId}
255 }
256 flowIDList = appendUnique(flowIDList, deviceFlow.FlowId)
257 f.flowsUsedByGemPort[gemPK] = flowIDList
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +0530258 // update the flowids for a gem to the KVstore
259 f.resourceMgr.UpdateFlowIDsForGem(uint32(deviceFlow.AccessIntfId), uint32(deviceFlow.GemportId), flowIDList)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400260}
261
salmansiddiqui7ac62132019-08-22 03:58:50 +0000262func (f *OpenOltFlowMgr) divideAndAddFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32,
263 classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpID uint32,
264 UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) {
Gamze Abakafee36392019-10-03 11:17:24 +0000265 var allocID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530266 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400267 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530268
Manikkaraj kb1d51442019-07-23 10:41:02 -0400269 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
salmansiddiqui7ac62132019-08-22 03:58:50 +0000270 "classifier": classifierInfo, "action": actionInfo, "UsMeterID": UsMeterID, "DsMeterID": DsMeterID, "TpID": TpID})
Matt Jeanneret77199612019-07-26 18:08:35 -0400271 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
272 // is because the flow is an NNI flow and there would be no onu resources associated with it
273 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400274 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400275 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530276 return
277 }
278
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530279 uni := getUniPortPath(intfID, int32(onuID), int32(uniID))
Manikkaraj kb1d51442019-07-23 10:41:02 -0400280 log.Debugw("Uni port name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530281
282 tpLockMapKey := tpLockKey{intfID, onuID, uniID}
283 if f.perUserFlowHandleLock.TryLock(tpLockMapKey) {
284 allocID, gemPorts, TpInst = f.createTcontGemports(intfID, onuID, uniID, uni, portNo, TpID, UsMeterID, DsMeterID, flowMetadata)
285 if allocID == 0 || gemPorts == nil || TpInst == nil {
286 log.Error("alloc-id-gem-ports-tp-unavailable")
287 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
288 return
289 }
290 args := make(map[string]uint32)
291 args[IntfID] = intfID
292 args[OnuID] = onuID
293 args[UniID] = uniID
294 args[PortNo] = portNo
295 args[AllocID] = allocID
296
297 /* Flows can be added specific to gemport if p-bits are received.
298 * If no pbit mentioned then adding flows for all gemports
299 */
300 f.checkAndAddFlow(args, classifierInfo, actionInfo, flow, TpInst, gemPorts, TpID, uni)
301 f.perUserFlowHandleLock.Unlock(tpLockMapKey)
302 } else {
303 log.Errorw("failed to acquire per user flow handle lock",
304 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400305 return
306 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530307}
308
salmansiddiqui7ac62132019-08-22 03:58:50 +0000309// CreateSchedulerQueues creates traffic schedulers on the device with the given scheduler configuration and traffic shaping info
Gamze Abakafee36392019-10-03 11:17:24 +0000310func (f *OpenOltFlowMgr) CreateSchedulerQueues(sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400311
Gamze Abakafee36392019-10-03 11:17:24 +0000312 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": sq.direction, "IntfID": sq.intfID,
313 "OnuID": sq.onuID, "UniID": sq.uniID, "TpID": sq.tpID, "MeterID": sq.meterID,
314 "TpInst": sq.tpInst, "flowMetadata": sq.flowMetadata})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400315
Gamze Abakafee36392019-10-03 11:17:24 +0000316 Direction, err := verifyMeterIDAndGetDirection(sq.meterID, sq.direction)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000317 if err != nil {
318 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400319 }
320
321 /* Lets make a simple assumption that if the meter-id is present on the KV store,
322 * then the scheduler and queues configuration is applied on the OLT device
323 * in the given direction.
324 */
salmansiddiqui7ac62132019-08-22 03:58:50 +0000325
Manikkaraj kb1d51442019-07-23 10:41:02 -0400326 var SchedCfg *tp_pb.SchedulerConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000327 KvStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400328 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000329 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 -0400330 return err
331 }
332 if KvStoreMeter != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000333 if KvStoreMeter.MeterId == sq.meterID {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400334 log.Debug("Scheduler already created for upstream")
335 return nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400336 }
Gamze Abakafee36392019-10-03 11:17:24 +0000337 log.Errorw("Dynamic meter update not supported", log.Fields{"KvStoreMeterId": KvStoreMeter.MeterId, "MeterID-in-flow": sq.meterID})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000338 return errors.New("invalid-meter-id-in-flow")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400339 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000340
Gamze Abakafee36392019-10-03 11:17:24 +0000341 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterID": sq.meterID, "Direction": Direction})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000342
Gamze Abakafee36392019-10-03 11:17:24 +0000343 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000344 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Gamze Abakafee36392019-10-03 11:17:24 +0000345 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000346 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400347 }
Girish Kumar8f73fe02019-12-09 13:19:37 +0000348
349 if err != nil {
350 log.Errorw("Unable to get Scheduler config", log.Fields{"IntfID": sq.intfID, "Direction": sq.direction, "Error": err})
351 return err
352 }
353
Manikkaraj kb1d51442019-07-23 10:41:02 -0400354 var meterConfig *ofp.OfpMeterConfig
Gamze Abakafee36392019-10-03 11:17:24 +0000355 if sq.flowMetadata != nil {
356 for _, meter := range sq.flowMetadata.Meters {
357 if sq.meterID == meter.MeterId {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400358 meterConfig = meter
359 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
360 break
361 }
362 }
363 } else {
364 log.Error("Flow-metadata-is-not-present-in-flow")
365 }
366 if meterConfig == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000367 log.Errorw("Could-not-get-meterbands-from-flowMetadata", log.Fields{"flowMetadata": sq.flowMetadata,
368 "MeterID": sq.meterID})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000369 return errors.New("failed-to-get-meter-from-flowMetadata")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400370 } else if len(meterConfig.Bands) < MaxMeterBand {
Gamze Abakafee36392019-10-03 11:17:24 +0000371 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterID": sq.meterID})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000372 return errors.New("invalid-number-of-bands-in-meter")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400373 }
374 cir := meterConfig.Bands[0].Rate
375 cbs := meterConfig.Bands[0].BurstSize
376 eir := meterConfig.Bands[1].Rate
377 ebs := meterConfig.Bands[1].BurstSize
378 pir := cir + eir
379 pbs := cbs + ebs
380 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
381
Gamze Abakafee36392019-10-03 11:17:24 +0000382 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Manikkaraj kb1d51442019-07-23 10:41:02 -0400383
Girish Kumar8f73fe02019-12-09 13:19:37 +0000384 if err := f.pushSchedulerQueuesToDevice(sq, TrafficShaping, TrafficSched); err != nil {
385 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 -0400386 return err
387 }
388
salmansiddiqui7ac62132019-08-22 03:58:50 +0000389 /* After we successfully applied the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400390 * store the meter id on the KV store, for further reference.
391 */
Gamze Abakafee36392019-10-03 11:17:24 +0000392 if err := f.resourceMgr.UpdateMeterIDForOnu(Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID, meterConfig); err != nil {
393 log.Error("Failed to update meter id for onu %d, meterid %d", sq.onuID, sq.meterID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400394 return err
395 }
396 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
397 "Meter": meterConfig})
398 return nil
399}
400
Girish Kumar8f73fe02019-12-09 13:19:37 +0000401func (f *OpenOltFlowMgr) pushSchedulerQueuesToDevice(sq schedQueue, TrafficShaping *tp_pb.TrafficShapingInfo, TrafficSched []*tp_pb.TrafficScheduler) error {
402
403 trafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
404
405 if err != nil {
406 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
407 return err
408 }
409
410 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": sq.direction, "TrafficScheds": TrafficSched})
411 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(context.Background(), &tp_pb.TrafficSchedulers{
412 IntfId: sq.intfID, OnuId: sq.onuID,
413 UniId: sq.uniID, PortNo: sq.uniPort,
414 TrafficScheds: TrafficSched}); err != nil {
415 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
416 return err
417 }
418
419 // On receiving the CreateTrafficQueues request, the driver should create corresponding
420 // downstream queues.
421 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": sq.direction, "TrafficQueues": trafficQueues})
422 if _, err := f.deviceHandler.Client.CreateTrafficQueues(context.Background(),
423 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
424 UniId: sq.uniID, PortNo: sq.uniPort,
425 TrafficQueues: trafficQueues}); err != nil {
426 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
427 return err
428 }
429
430 return nil
431}
432
salmansiddiqui7ac62132019-08-22 03:58:50 +0000433// RemoveSchedulerQueues removes the traffic schedulers from the device based on the given scheduler configuration and traffic shaping info
Gamze Abakafee36392019-10-03 11:17:24 +0000434func (f *OpenOltFlowMgr) RemoveSchedulerQueues(sq schedQueue) error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400435
436 var Direction string
437 var SchedCfg *tp_pb.SchedulerConfig
438 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000439 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": sq.direction, "IntfID": sq.intfID,
440 "OnuID": sq.onuID, "UniID": sq.uniID, "UniPort": sq.uniPort})
441 if sq.direction == tp_pb.Direction_UPSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000442 SchedCfg, err = f.techprofile[sq.intfID].GetUsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400443 Direction = "upstream"
Gamze Abakafee36392019-10-03 11:17:24 +0000444 } else if sq.direction == tp_pb.Direction_DOWNSTREAM {
Girish Kumar8f73fe02019-12-09 13:19:37 +0000445 SchedCfg, err = f.techprofile[sq.intfID].GetDsScheduler(sq.tpInst)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400446 Direction = "downstream"
447 }
448
Girish Kumar8f73fe02019-12-09 13:19:37 +0000449 if err != nil {
450 log.Errorw("Unable to get Scheduler config", log.Fields{"IntID": sq.intfID, "Direction": sq.direction, "Error": err})
451 return err
452 }
453
Gamze Abakafee36392019-10-03 11:17:24 +0000454 KVStoreMeter, err := f.resourceMgr.GetMeterIDForOnu(Direction, sq.intfID, sq.onuID, sq.uniID, sq.tpID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400455 if err != nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000456 log.Errorf("Failed to get Meter for Onu %d", sq.onuID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400457 return err
458 }
459 if KVStoreMeter == nil {
Gamze Abakafee36392019-10-03 11:17:24 +0000460 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 -0400461 return nil
462 }
463 cir := KVStoreMeter.Bands[0].Rate
464 cbs := KVStoreMeter.Bands[0].BurstSize
465 eir := KVStoreMeter.Bands[1].Rate
466 ebs := KVStoreMeter.Bands[1].BurstSize
467 pir := cir + eir
468 pbs := cbs + ebs
469
470 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
471
Gamze Abakafee36392019-10-03 11:17:24 +0000472 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst, SchedCfg, TrafficShaping)}
Girish Kumar8f73fe02019-12-09 13:19:37 +0000473
474 TrafficQueues, err := f.techprofile[sq.intfID].GetTrafficQueues(sq.tpInst, sq.direction)
475 if err != nil {
476 log.Errorw("Unable to construct traffic queue configuration", log.Fields{"intfID": sq.intfID, "direction": sq.direction})
477 return err
478 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400479
480 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(context.Background(),
Gamze Abakafee36392019-10-03 11:17:24 +0000481 &tp_pb.TrafficQueues{IntfId: sq.intfID, OnuId: sq.onuID,
482 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400483 TrafficQueues: TrafficQueues}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000484 log.Errorw("Failed to remove traffic queues", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400485 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400486 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000487 log.Debug("Removed traffic queues successfully")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400488 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(context.Background(), &tp_pb.TrafficSchedulers{
Gamze Abakafee36392019-10-03 11:17:24 +0000489 IntfId: sq.intfID, OnuId: sq.onuID,
490 UniId: sq.uniID, PortNo: sq.uniPort,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400491 TrafficScheds: TrafficSched}); err != nil {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000492 log.Errorw("failed to remove traffic schedulers", log.Fields{"error": err})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400493 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400494 }
495
salmansiddiqui7ac62132019-08-22 03:58:50 +0000496 log.Debug("Removed traffic schedulers successfully")
497
498 /* After we successfully remove the scheduler configuration on the OLT device,
Manikkaraj kb1d51442019-07-23 10:41:02 -0400499 * delete the meter id on the KV store.
500 */
Gamze Abakafee36392019-10-03 11:17:24 +0000501 err = f.resourceMgr.RemoveMeterIDForOnu(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 remove meter for onu %d, meter id %d", sq.onuID, KVStoreMeter.MeterId)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000504 return err
Manikkaraj kb1d51442019-07-23 10:41:02 -0400505 }
506 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
507 return err
508}
509
Gamze Abakafee36392019-10-03 11:17:24 +0000510// This function allocates tconts and GEM ports for an ONU
511func (f *OpenOltFlowMgr) createTcontGemports(intfID uint32, onuID uint32, uniID uint32, uni string, uniPort uint32, TpID uint32, UsMeterID uint32, DsMeterID uint32, flowMetadata *voltha.FlowMetadata) (uint32, []uint32, *tp.TechProfile) {
512 var allocIDs []uint32
513 var allgemPortIDs []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530514 var gemPortIDs []uint32
Girish Gowdra3d633032019-12-10 16:37:05 +0530515 tpInstanceExists := false
Girish Kumar8f73fe02019-12-09 13:19:37 +0000516 var err error
Gamze Abakafee36392019-10-03 11:17:24 +0000517
518 allocIDs = f.resourceMgr.GetCurrentAllocIDsForOnu(intfID, onuID, uniID)
519 allgemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400520
521 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdra54934262019-11-13 14:19:55 +0530522
523 log.Infow("creating-new-tcont-and-gem", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
524
Manikkaraj kb1d51442019-07-23 10:41:02 -0400525 // Check tech profile instance already exists for derived port name
Girish Gowdra54934262019-11-13 14:19:55 +0530526 techProfileInstance, _ := f.techprofile[intfID].GetTPInstanceFromKVStore(TpID, tpPath)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000527 if techProfileInstance == nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530528 log.Infow("tp-instance-not-found--creating-new", log.Fields{"path": tpPath})
Girish Kumar8f73fe02019-12-09 13:19:37 +0000529 techProfileInstance, err = f.techprofile[intfID].CreateTechProfInstance(TpID, uni, intfID)
530 if err != nil {
Girish Gowdra54934262019-11-13 14:19:55 +0530531 // This should not happen, something wrong in KV backend transaction
Girish Kumar8f73fe02019-12-09 13:19:37 +0000532 log.Errorw("tp-instance-create-failed", log.Fields{"error": err, "tpID": TpID})
Gamze Abakafee36392019-10-03 11:17:24 +0000533 return 0, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530534 }
salmansiddiqui7ac62132019-08-22 03:58:50 +0000535 f.resourceMgr.UpdateTechProfileIDForOnu(intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530536 } else {
537 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
Girish Gowdra3d633032019-12-10 16:37:05 +0530538 tpInstanceExists = true
manikkaraj kbf256be2019-03-25 00:13:48 +0530539 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400540 if UsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000541 sq := schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
542 uniPort: uniPort, tpInst: techProfileInstance, meterID: UsMeterID, flowMetadata: flowMetadata}
543 if err := f.CreateSchedulerQueues(sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400544 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000545 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400546 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530547 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400548 if DsMeterID != 0 {
Gamze Abakafee36392019-10-03 11:17:24 +0000549 sq := schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: intfID, onuID: onuID, uniID: uniID, tpID: TpID,
550 uniPort: uniPort, tpInst: techProfileInstance, meterID: DsMeterID, flowMetadata: flowMetadata}
551 if err := f.CreateSchedulerQueues(sq); err != nil {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400552 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
Gamze Abakafee36392019-10-03 11:17:24 +0000553 return 0, nil, nil
Manikkaraj kb1d51442019-07-23 10:41:02 -0400554 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530555 }
Gamze Abakafee36392019-10-03 11:17:24 +0000556
557 allocID := techProfileInstance.UsScheduler.AllocID
Gamze Abakafee36392019-10-03 11:17:24 +0000558 for _, gem := range techProfileInstance.UpstreamGemPortAttributeList {
Gamze Abakafee36392019-10-03 11:17:24 +0000559 gemPortIDs = append(gemPortIDs, gem.GemportID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400560 }
Gamze Abakafee36392019-10-03 11:17:24 +0000561
Girish Gowdra3d633032019-12-10 16:37:05 +0530562 if tpInstanceExists {
563 return allocID, gemPortIDs, techProfileInstance
564 }
565
566 allocIDs = appendUnique(allocIDs, allocID)
567 for _, gemPortID := range gemPortIDs {
568 allgemPortIDs = appendUnique(allgemPortIDs, gemPortID)
569 }
570
Gamze Abakafee36392019-10-03 11:17:24 +0000571 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocIDs": allocIDs, "gemports": allgemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530572 // Send Tconts and GEM ports to KV store
Gamze Abakafee36392019-10-03 11:17:24 +0000573 f.storeTcontsGEMPortsIntoKVStore(intfID, onuID, uniID, allocIDs, allgemPortIDs)
salmansiddiqui7ac62132019-08-22 03:58:50 +0000574 return allocID, gemPortIDs, techProfileInstance
manikkaraj kbf256be2019-03-25 00:13:48 +0530575}
576
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700577func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530578
579 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700580 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530581 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700582 if err := f.resourceMgr.UpdateAllocIdsForOnu(intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530583 log.Error("Errow while uploading allocID to KV store")
584 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700585 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530586 log.Error("Errow while uploading GEMports to KV store")
587 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700588 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530589 log.Error("Errow while uploading gemtopon map to KV store")
590 }
591 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400592 for _, gemPort := range gemPortIDs {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700593 f.addGemPortToOnuInfoMap(intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400594 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530595}
596
597func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000598 var tpCount int
manikkaraj kbf256be2019-03-25 00:13:48 +0530599 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
salmansiddiqui7ac62132019-08-22 03:58:50 +0000600 for _, intfID := range techRange.IntfIds {
601 f.techprofile[intfID] = f.resourceMgr.ResourceMgrs[uint32(intfID)].TechProfileMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400602 tpCount++
salmansiddiqui7ac62132019-08-22 03:58:50 +0000603 log.Debugw("Init tech profile done", log.Fields{"intfID": intfID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530604 }
605 }
606 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400607 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530608 log.Errorw("Error while populating techprofile",
Manikkaraj kb1d51442019-07-23 10:41:02 -0400609 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
salmansiddiqui7ac62132019-08-22 03:58:50 +0000610 return errors.New("error while populating techprofile mgrs")
manikkaraj kbf256be2019-03-25 00:13:48 +0530611 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400612 log.Infow("Populated techprofile for ponports successfully",
613 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530614 return nil
615}
616
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700617func (f *OpenOltFlowMgr) addUpstreamDataFlow(intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530618 portNo uint32, uplinkClassifier map[string]interface{},
619 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700620 allocID uint32, gemportID uint32) {
621 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530622 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700623 f.addHSIAFlow(intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700624 Upstream, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530625 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530626}
627
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700628func (f *OpenOltFlowMgr) addDownstreamDataFlow(intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530629 portNo uint32, downlinkClassifier map[string]interface{},
630 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700631 allocID uint32, gemportID uint32) {
632 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530633 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
634 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400635 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
636 if vlan, exists := downlinkClassifier[VlanVid]; exists {
637 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
David K. Bainbridge82efc492019-09-04 09:57:11 -0700638 if metadata, exists := downlinkClassifier[Metadata]; exists { // inport is filled in metadata by core
Manikkaraj kb1d51442019-07-23 10:41:02 -0400639 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
640 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
641 return
642 }
643 }
644 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530645 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400646
Manikkaraj k884c1242019-04-11 16:26:42 +0530647 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700648 downlinkAction[PopVlan] = true
Matt Jeannereted16b7c2019-11-01 13:31:35 -0400649 // vlan_vid is a uint32. must be type asserted as such or conversion fails
650 dlClVid, ok := downlinkClassifier[VlanVid].(uint32)
Girish Gowdra26f344b2019-10-23 14:39:13 +0530651 if ok {
652 downlinkAction[VlanVid] = dlClVid & 0xfff
653 } else {
654 log.Error("dl-classifier-vid-type-conversion-failed")
655 return
656 }
657
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700658 f.addHSIAFlow(intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700659 Downstream, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530660}
661
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700662func (f *OpenOltFlowMgr) addHSIAFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Manikkaraj k884c1242019-04-11 16:26:42 +0530663 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700664 allocID uint32, gemPortID uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530665 var networkIntfID uint32
Manikkaraj k884c1242019-04-11 16:26:42 +0530666 /* One of the OLT platform (Broadcom BAL) requires that symmetric
667 flows require the same flow_id to be used across UL and DL.
668 Since HSIA flow is the only symmetric flow currently, we need to
669 re-use the flow_id across both direction. The 'flow_category'
670 takes priority over flow_cookie to find any available HSIA_FLOW
671 id for the ONU.
672 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700673 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
674 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530675 "logicalFlow": *logicalFlow})
Gamze Abakafee36392019-10-03 11:17:24 +0000676 var vlanPbit uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400677 if _, ok := classifier[VlanPcp]; ok {
Gamze Abakafee36392019-10-03 11:17:24 +0000678 vlanPbit = classifier[VlanPcp].(uint32)
679 log.Debugw("Found pbit in the flow", log.Fields{"VlanPbit": vlanPbit})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400680 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700681 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
Girish Gowdra3d633032019-12-10 16:37:05 +0530682 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
683 log.Debug("Flow-exists--not-re-adding")
684 return
685 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530686 flowID, err := f.resourceMgr.GetFlowID(intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, HsiaFlow, vlanPbit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530687 if err != nil {
688 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
689 return
690 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700691 var classifierProto *openoltpb2.Classifier
692 var actionProto *openoltpb2.Action
Manikkaraj k884c1242019-04-11 16:26:42 +0530693 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
694 log.Error("Error in making classifier protobuf for hsia flow")
695 return
696 }
697 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
698 if actionProto = makeOpenOltActionField(action); actionProto == nil {
699 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
700 return
701 }
702 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530703 networkIntfID, err = getNniIntfID(classifier, action)
704 if err != nil {
705 log.Error("Failed to get nniIntf ID")
706 return
707 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700708 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
709 OnuId: int32(onuID),
710 UniId: int32(uniID),
salmansiddiqui7ac62132019-08-22 03:58:50 +0000711 FlowId: flowID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530712 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700713 AllocId: int32(allocID),
714 NetworkIntfId: int32(networkIntfID),
715 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530716 Classifier: classifierProto,
717 Action: actionProto,
718 Priority: int32(logicalFlow.Priority),
719 Cookie: logicalFlow.Cookie,
720 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400721 if ok := f.addFlowToDevice(logicalFlow, &flow); ok {
Manikkaraj k884c1242019-04-11 16:26:42 +0530722 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530723 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, HsiaFlow, flowID, logicalFlow.Id)
Manikkaraj k884c1242019-04-11 16:26:42 +0530724 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
725 flow.OnuId,
726 flow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400727 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530728 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
729 return
730 }
731 }
732}
Esin Karamanae41e2b2019-12-17 18:13:13 +0000733
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700734func (f *OpenOltFlowMgr) addDHCPTrapFlow(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 +0530735
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700736 var dhcpFlow openoltpb2.Flow
737 var actionProto *openoltpb2.Action
738 var classifierProto *openoltpb2.Classifier
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530739 var flowID uint32
740 networkIntfID, err := getNniIntfID(classifier, action)
741 if err != nil {
742 log.Error("Failed to get nniIntf ID")
743 return
744 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530745
746 // Clear the action map
747 for k := range action {
748 delete(action, k)
749 }
750
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700751 action[TrapToHost] = true
752 classifier[UDPSrc] = uint32(68)
753 classifier[UDPDst] = uint32(67)
754 classifier[PacketTagType] = SingleTag
755 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530756
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700757 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
Girish Gowdra3d633032019-12-10 16:37:05 +0530758 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
759 log.Debug("Flow-exists--not-re-adding")
760 return
761 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530762
Girish Gowdra3d633032019-12-10 16:37:05 +0530763 flowID, err = f.resourceMgr.GetFlowID(intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, DhcpFlow, 0 /*classifier[VLAN_PCP].(uint32)*/)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530764
765 if err != nil {
Girish Gowdra3d633032019-12-10 16:37:05 +0530766 log.Errorw("flowId unavailable for UL DHCP", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530767 return
768 }
769
770 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
771
772 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
773 log.Error("Error in making classifier protobuf for ul flow")
774 return
775 }
776 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
777 if actionProto = makeOpenOltActionField(action); actionProto == nil {
778 log.Error("Error in making action protobuf for ul flow")
779 return
780 }
781
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700782 dhcpFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
783 OnuId: int32(onuID),
784 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530785 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700786 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700787 AllocId: int32(allocID),
788 NetworkIntfId: int32(networkIntfID),
789 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530790 Classifier: classifierProto,
791 Action: actionProto,
792 Priority: int32(logicalFlow.Priority),
793 Cookie: logicalFlow.Cookie,
794 PortNo: portNo}
795
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400796 if ok := f.addFlowToDevice(logicalFlow, &dhcpFlow); ok {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530797 log.Debug("DHCP UL flow added to device successfully")
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530798 flowsToKVStore := f.getUpdatedFlowInfo(&dhcpFlow, flowStoreCookie, "DHCP", flowID, logicalFlow.Id)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530799 if err := f.updateFlowInfoToKVStore(dhcpFlow.AccessIntfId,
800 dhcpFlow.OnuId,
801 dhcpFlow.UniId,
802 dhcpFlow.FlowId, flowsToKVStore); err != nil {
803 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
804 return
805 }
806 }
807
manikkaraj kbf256be2019-03-25 00:13:48 +0530808 return
809}
810
Esin Karamanae41e2b2019-12-17 18:13:13 +0000811//addIGMPTrapFlow creates IGMP trap-to-host flow
812func (f *OpenOltFlowMgr) addIGMPTrapFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
813 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32) {
814 f.addUpstreamTrapFlow(intfID, onuID, uniID, portNo, classifier, action, logicalFlow, allocID, gemPortID, IgmpFlow)
815}
816
817//addUpstreamTrapFlow creates a trap-to-host flow
818func (f *OpenOltFlowMgr) addUpstreamTrapFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
819 action map[string]interface{}, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, flowType string) {
820
821 var flow openoltpb2.Flow
822 var actionProto *openoltpb2.Action
823 var classifierProto *openoltpb2.Classifier
824
825 networkIntfID, err := getNniIntfID(classifier, action)
826 if err != nil {
827 log.Error("Failed to get nniIntf ID")
828 return
829 }
830
831 // Clear the action map
832 for k := range action {
833 delete(action, k)
834 }
835
836 action[TrapToHost] = true
837 classifier[PacketTagType] = SingleTag
838 delete(classifier, VlanVid)
839
840 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
841 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkIntfID), int32(onuID), int32(uniID), flowStoreCookie); present {
842 log.Debug("Flow-exists--not-re-adding")
843 return
844 }
845
846 flowID, err := f.resourceMgr.GetFlowID(intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, flowType, 0, 0 /*classifier[VLAN_PCP].(uint32)*/)
847
848 if err != nil {
849 log.Errorw("flowId unavailable for upstream trap flow", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie, "flowType": flowType})
850 return
851 }
852
853 log.Debugw("Creating upstream trap flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID, "flowType": flowType})
854
855 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
856 log.Error("Error in making classifier protobuf for ul flow")
857 return
858 }
859 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
860 if actionProto = makeOpenOltActionField(action); actionProto == nil {
861 log.Error("Error in making action protobuf for ul flow")
862 return
863 }
864
865 flow = openoltpb2.Flow{AccessIntfId: int32(intfID),
866 OnuId: int32(onuID),
867 UniId: int32(uniID),
868 FlowId: flowID,
869 FlowType: Upstream,
870 AllocId: int32(allocID),
871 NetworkIntfId: int32(networkIntfID),
872 GemportId: int32(gemPortID),
873 Classifier: classifierProto,
874 Action: actionProto,
875 Priority: int32(logicalFlow.Priority),
876 Cookie: logicalFlow.Cookie,
877 PortNo: portNo}
878
879 if ok := f.addFlowToDevice(logicalFlow, &flow); ok {
880 log.Debugf("%s UL flow added to device successfully", flowType)
881
882 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, flowType, flowID, logicalFlow.Id)
883 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
884 flow.OnuId,
885 flow.UniId,
886 flow.FlowId, flowsToKVStore); err != nil {
887 log.Errorw("Error uploading UL flow into KV store", log.Fields{"flow": flow, "error": err})
888 return
889 }
890 }
891
892 return
893}
894
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700895// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530896func (f *OpenOltFlowMgr) addEAPOLFlow(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 -0700897 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 +0530898
899 uplinkClassifier := make(map[string]interface{})
900 uplinkAction := make(map[string]interface{})
Girish Gowdra3d633032019-12-10 16:37:05 +0530901
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700902 var upstreamFlow openoltpb2.Flow
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530903 var networkIntfID uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530904
905 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700906 uplinkClassifier[EthType] = uint32(EapEthType)
907 uplinkClassifier[PacketTagType] = SingleTag
908 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530909 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700910 uplinkAction[TrapToHost] = true
911 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
Girish Gowdra3d633032019-12-10 16:37:05 +0530912 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(intfID), int32(onuID), int32(uniID), flowStoreCookie); present {
913 log.Debug("Flow-exists--not-re-adding")
914 return
915 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530916 //Add Uplink EAPOL Flow
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530917 uplinkFlowID, err := f.resourceMgr.GetFlowID(intfID, int32(onuID), int32(uniID), gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530918 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700919 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manikkaraj k884c1242019-04-11 16:26:42 +0530920 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530921 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700922 var classifierProto *openoltpb2.Classifier
923 var actionProto *openoltpb2.Action
924 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530925
926 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
927 log.Error("Error in making classifier protobuf for ul flow")
928 return
929 }
930 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
931 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
932 log.Error("Error in making action protobuf for ul flow")
933 return
934 }
935 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530936 networkIntfID, err = getNniIntfID(classifier, action)
937 if err != nil {
938 log.Error("Failed to get nniIntf ID")
939 return
940 }
941
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700942 upstreamFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
943 OnuId: int32(onuID),
944 UniId: int32(uniID),
945 FlowId: uplinkFlowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -0700946 FlowType: Upstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700947 AllocId: int32(allocID),
948 NetworkIntfId: int32(networkIntfID),
949 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +0530950 Classifier: classifierProto,
951 Action: actionProto,
952 Priority: int32(logicalFlow.Priority),
953 Cookie: logicalFlow.Cookie,
954 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400955 if ok := f.addFlowToDevice(logicalFlow, &upstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530956 log.Debug("EAPOL UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400957 flowCategory := "EAPOL"
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +0530958 flowsToKVStore := f.getUpdatedFlowInfo(&upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID, logicalFlow.Id)
manikkaraj kbf256be2019-03-25 00:13:48 +0530959 if err := f.updateFlowInfoToKVStore(upstreamFlow.AccessIntfId,
960 upstreamFlow.OnuId,
961 upstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400962 upstreamFlow.FlowId,
963 /* lowCategory, */
964 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530965 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
966 return
967 }
968 }
Girish Gowdra3d633032019-12-10 16:37:05 +0530969
manikkaraj kbf256be2019-03-25 00:13:48 +0530970 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
971}
972
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700973func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openoltpb2.Classifier {
974 var classifier openoltpb2.Classifier
David K. Bainbridge82efc492019-09-04 09:57:11 -0700975
976 classifier.EthType, _ = classifierInfo[EthType].(uint32)
977 classifier.IpProto, _ = classifierInfo[IPProto].(uint32)
978 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
979 vid := vlanID & VlanvIDMask
980 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -0400981 classifier.OVid = vid
982 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530983 }
David K. Bainbridge82efc492019-09-04 09:57:11 -0700984 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
985 vid := uint32(metadata)
986 if vid != ReservedVlan {
Harsh Awasthiea45af72019-08-26 02:39:00 -0400987 classifier.IVid = vid
988 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530989 }
David K. Bainbridge82efc492019-09-04 09:57:11 -0700990 if vlanPcp, ok := classifierInfo[VlanPcp].(uint32); ok {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400991 if vlanPcp == 0 {
992 classifier.OPbits = VlanPCPMask
993 } else {
David K. Bainbridge82efc492019-09-04 09:57:11 -0700994 classifier.OPbits = vlanPcp & VlanPCPMask
Manikkaraj kb1d51442019-07-23 10:41:02 -0400995 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530996 }
David K. Bainbridge82efc492019-09-04 09:57:11 -0700997 classifier.SrcPort, _ = classifierInfo[UDPSrc].(uint32)
998 classifier.DstPort, _ = classifierInfo[UDPDst].(uint32)
999 classifier.DstIp, _ = classifierInfo[Ipv4Dst].(uint32)
1000 classifier.SrcIp, _ = classifierInfo[Ipv4Src].(uint32)
1001 if pktTagType, ok := classifierInfo[PacketTagType].(string); ok {
1002 classifier.PktTagType = pktTagType
1003
1004 switch pktTagType {
1005 case SingleTag:
1006 case DoubleTag:
1007 case Untagged:
1008 default:
manikkaraj kbf256be2019-03-25 00:13:48 +05301009 log.Error("Invalid tag type in classifier") // should not hit
1010 return nil
1011 }
1012 }
1013 return &classifier
1014}
1015
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001016func makeOpenOltActionField(actionInfo map[string]interface{}) *openoltpb2.Action {
1017 var actionCmd openoltpb2.ActionCmd
1018 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +05301019 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001020 if _, ok := actionInfo[PopVlan]; ok {
1021 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301022 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001023 } else if _, ok := actionInfo[PushVlan]; ok {
1024 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +05301025 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001026 } else if _, ok := actionInfo[TrapToHost]; ok {
1027 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +05301028 } else {
1029 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
1030 return nil
1031 }
1032 return &action
1033}
1034
Manikkaraj kb1d51442019-07-23 10:41:02 -04001035func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
1036 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +05301037}
1038
Gamze Abakafee36392019-10-03 11:17:24 +00001039// DeleteTechProfileInstances removes the tech profile instances from persistent storage
1040func (f *OpenOltFlowMgr) DeleteTechProfileInstances(intfID uint32, onuID uint32, uniID uint32, sn string) error {
1041 tpIDList := f.resourceMgr.GetTechProfileIDForOnu(intfID, onuID, uniID)
Devmalya Paul495b94a2019-08-27 19:42:00 -04001042 uniPortName := fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
Gamze Abakafee36392019-10-03 11:17:24 +00001043 for _, tpID := range tpIDList {
1044 if err := f.DeleteTechProfileInstance(intfID, onuID, uniID, uniPortName, tpID); err != nil {
1045 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 +05301046 // return err
1047 // We should continue to delete tech-profile instances for other TP IDs
Gamze Abakafee36392019-10-03 11:17:24 +00001048 }
1049 }
1050 return nil
1051}
1052
1053// DeleteTechProfileInstance removes the tech profile instance from persistent storage
1054func (f *OpenOltFlowMgr) DeleteTechProfileInstance(intfID uint32, onuID uint32, uniID uint32, uniPortName string, tpID uint32) error {
1055 if uniPortName == "" {
1056 uniPortName = fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1057 }
Devmalya Paul495b94a2019-08-27 19:42:00 -04001058 if err := f.techprofile[intfID].DeleteTechProfileInstance(tpID, uniPortName); err != nil {
1059 log.Debugw("Failed-to-delete-tp-instance-from-kv-store", log.Fields{"tp-id": tpID, "uni-port-name": uniPortName})
1060 return err
1061 }
1062 return nil
1063}
1064
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001065func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +05301066 if len(classifier) == 0 { // should never happen
1067 log.Error("Invalid classfier object")
1068 return 0
1069 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301070 log.Debugw("generating flow store cookie", log.Fields{"classifier": classifier, "gemPortID": gemPortID})
manikkaraj kbf256be2019-03-25 00:13:48 +05301071 var jsonData []byte
1072 var flowString string
1073 var err error
1074 // TODO: Do we need to marshall ??
1075 if jsonData, err = json.Marshal(classifier); err != nil {
1076 log.Error("Failed to encode classifier")
1077 return 0
1078 }
1079 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001080 if gemPortID != 0 {
1081 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +05301082 }
1083 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001084 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +05301085 hash := big.NewInt(0)
1086 hash.SetBytes(h.Sum(nil))
Girish Gowdra3d633032019-12-10 16:37:05 +05301087 generatedHash := hash.Uint64()
1088 log.Debugw("hash generated", log.Fields{"hash": generatedHash})
1089 return generatedHash
manikkaraj kbf256be2019-03-25 00:13:48 +05301090}
1091
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301092func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openoltpb2.Flow, flowStoreCookie uint64, flowCategory string, deviceFlowID uint32, logicalFlowID uint64) *[]rsrcMgr.FlowInfo {
1093 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie, LogicalFlowID: logicalFlowID}}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001094 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001095 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1096 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1097 */
1098 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001099 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001100 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001101 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001102 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001103 // Get existing flows matching flowid for given subscriber from KV store
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301104 existingFlows := f.resourceMgr.GetFlowIDInfo(intfID, flow.OnuId, flow.UniId, flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001105 if existingFlows != nil {
1106 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001107 //for _, f := range *existingFlows {
1108 // flows = append(flows, f)
1109 //}
1110 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001111 }
1112 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 +05301113 return &flows
1114}
1115
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001116//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1117// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1118// var intfId uint32
1119// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1120// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1121// */
1122// if flow.AccessIntfId != -1 {
1123// intfId = uint32(flow.AccessIntfId)
1124// } else {
1125// intfId = uint32(flow.NetworkIntfId)
1126// }
1127// // Get existing flows matching flowid for given subscriber from KV store
1128// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1129// if existingFlows != nil {
1130// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1131// for _, f := range *existingFlows {
1132// flows = append(flows, f)
1133// }
1134// }
1135// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1136// return &flows
1137//}
1138
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001139func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(intfID int32, onuID int32, uniID int32, flowID uint32, flows *[]rsrcMgr.FlowInfo) error {
manikkaraj k17652a72019-05-06 09:06:36 -04001140 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001141 if err := f.resourceMgr.UpdateFlowIDInfo(intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001142 log.Debug("Error while Storing flow into KV store")
1143 return err
1144 }
1145 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301146 return nil
1147}
1148
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001149func (f *OpenOltFlowMgr) addFlowToDevice(logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) bool {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001150
1151 var intfID uint32
1152 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1153 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1154 */
1155 if deviceFlow.AccessIntfId != -1 {
1156 intfID = uint32(deviceFlow.AccessIntfId)
1157 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001158 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001159 intfID = uint32(deviceFlow.NetworkIntfId)
1160 }
1161
manikkaraj kbf256be2019-03-25 00:13:48 +05301162 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1163 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001164
1165 st, _ := status.FromError(err)
1166 if st.Code() == codes.AlreadyExists {
Gamze Abakafee36392019-10-03 11:17:24 +00001167 log.Debug("Flow already exists", log.Fields{"err": err, "deviceFlow": deviceFlow})
Girish Gowdra3d633032019-12-10 16:37:05 +05301168 return true
manikkaraj kbf256be2019-03-25 00:13:48 +05301169 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001170
1171 if err != nil {
1172 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
Devmalya Paul495b94a2019-08-27 19:42:00 -04001173 f.resourceMgr.FreeFlowID(intfID, deviceFlow.OnuId, deviceFlow.UniId, deviceFlow.FlowId)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001174 return false
1175 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001176 f.registerFlow(logicalFlow, deviceFlow)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301177 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001178 return true
1179}
1180
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001181func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) bool {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001182 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1183 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1184 if err != nil {
serkant.uluderya245caba2019-09-24 23:15:29 -07001185 if f.deviceHandler.device.ConnectStatus == common.ConnectStatus_UNREACHABLE {
1186 log.Warnw("Can not remove flow from device since it's unreachable", log.Fields{"err": err, "deviceFlow": deviceFlow})
1187 //Assume the flow is removed
1188 return true
1189 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001190 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
1191 return false
serkant.uluderya245caba2019-09-24 23:15:29 -07001192
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001193 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001194 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +05301195 return true
1196}
1197
1198/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1199 //update core flows_proxy : flows_proxy.update('/', flows)
1200}
1201
1202func generateStoredId(flowId uint32, direction string)uint32{
1203
David K. Bainbridge82efc492019-09-04 09:57:11 -07001204 if direction == Upstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301205 log.Debug("Upstream flow shifting flowid")
1206 return ((0x1 << 15) | flowId)
David K. Bainbridge82efc492019-09-04 09:57:11 -07001207 }else if direction == Downstream{
manikkaraj kbf256be2019-03-25 00:13:48 +05301208 log.Debug("Downstream flow not shifting flowid")
1209 return flowId
1210 }else{
1211 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1212 return flowId
1213 }
1214}
1215
1216*/
1217
Humera Kouser94d7a842019-08-25 19:04:32 -04001218func (f *OpenOltFlowMgr) addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
1219
1220 classifierInfo := make(map[string]interface{})
1221 actionInfo := make(map[string]interface{})
1222
1223 classifierInfo[EthType] = uint32(LldpEthType)
1224 classifierInfo[PacketTagType] = Untagged
1225 actionInfo[TrapToHost] = true
1226
1227 // LLDP flow is installed to trap LLDP packets on the NNI port.
1228 // We manage flow_id resource pool on per PON port basis.
1229 // Since this situation is tricky, as a hack, we pass the NNI port
1230 // index (network_intf_id) as PON port Index for the flow_id resource
1231 // pool. Also, there is no ONU Id available for trapping LLDP packets
1232 // on NNI port, use onu_id as -1 (invalid)
1233 // ****************** CAVEAT *******************
1234 // This logic works if the NNI Port Id falls within the same valid
1235 // range of PON Port Ids. If this doesn't work for some OLT Vendor
1236 // we need to have a re-look at this.
1237 // *********************************************
1238
1239 var onuID = -1
1240 var uniID = -1
1241 var gemPortID = -1
1242
1243 var networkInterfaceID = IntfIDFromNniPortNum(portNo)
1244 var flowStoreCookie = getFlowStoreCookie(classifierInfo, uint32(0))
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301245 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
Humera Kouser94d7a842019-08-25 19:04:32 -04001246 log.Debug("Flow-exists--not-re-adding")
1247 return
1248 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301249 flowID, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
Humera Kouser94d7a842019-08-25 19:04:32 -04001250
1251 if err != nil {
1252 log.Errorw("Flow id unavailable for LLDP traponNNI flow", log.Fields{"error": err})
1253 return
1254 }
1255 var classifierProto *openoltpb2.Classifier
1256 var actionProto *openoltpb2.Action
1257 if classifierProto = makeOpenOltClassifierField(classifierInfo); classifierProto == nil {
1258 log.Error("Error in making classifier protobuf for LLDP trap on nni flow")
1259 return
1260 }
1261 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1262 if actionProto = makeOpenOltActionField(actionInfo); actionProto == nil {
1263 log.Error("Error in making action protobuf for LLDP trap on nni flow")
1264 return
1265 }
1266 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1267
1268 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1269 OnuId: int32(onuID), // OnuId not required
1270 UniId: int32(uniID), // UniId not used
1271 FlowId: flowID,
1272 FlowType: Downstream,
1273 NetworkIntfId: int32(networkInterfaceID),
1274 GemportId: int32(gemPortID),
1275 Classifier: classifierProto,
1276 Action: actionProto,
1277 Priority: int32(flow.Priority),
1278 Cookie: flow.Cookie,
1279 PortNo: portNo}
1280 if ok := f.addFlowToDevice(flow, &downstreamflow); ok {
1281 log.Debug("LLDP trap on NNI flow added to device successfully")
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301282 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowID, flow.Id)
Humera Kouser94d7a842019-08-25 19:04:32 -04001283 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceID),
1284 int32(onuID),
1285 int32(uniID),
1286 flowID, flowsToKVStore); err != nil {
1287 log.Errorw("Error uploading LLDP flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1288 }
1289 }
1290 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301291}
1292
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301293func getUniPortPath(intfID uint32, onuID int32, uniID int32) string {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001294 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1295}
1296
1297//getOnuChildDevice to fetch onu
1298func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1299 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1300 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
1301 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301302 if onuDevice == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001303 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301304 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +05301305 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301306 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1307 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301308}
1309
1310func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001311 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301312 return nil
1313}
1314
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001315func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1316 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301317}
1318
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001319func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001320 if id>>15 == 0x1 {
David K. Bainbridge82efc492019-09-04 09:57:11 -07001321 return id & 0x7fff, Upstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001322 }
David K. Bainbridge82efc492019-09-04 09:57:11 -07001323 return id, Downstream
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001324}
1325
Girish Gowdra6b130582019-11-20 16:45:20 +05301326func (f *OpenOltFlowMgr) sendDeleteGemPortToChild(intfID uint32, onuID uint32, uniID uint32, gemPortID uint32, tpPath string) error {
1327 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1328 if err != nil {
1329 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1330 return err
1331 }
1332
1333 delGemPortMsg := &ic.InterAdapterDeleteGemPortMessage{UniId: uniID, TpPath: tpPath, GemPortId: gemPortID}
1334 log.Debugw("sending gem port delete to openonu adapter", log.Fields{"msg": *delGemPortMsg})
1335 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1336 delGemPortMsg,
1337 ic.InterAdapterMessageType_DELETE_GEM_PORT_REQUEST,
1338 f.deviceHandler.deviceType,
1339 onuDevice.Type,
1340 onuDevice.Id,
1341 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1342 log.Errorw("failure sending del gem port to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1343 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1344 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1345 return sendErr
1346 }
1347 log.Debugw("success sending del gem port to onu adapter", log.Fields{"msg": delGemPortMsg})
1348 return nil
1349}
1350
1351func (f *OpenOltFlowMgr) sendDeleteTcontToChild(intfID uint32, onuID uint32, uniID uint32, allocID uint32, tpPath string) error {
1352 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
1353 if err != nil {
1354 log.Errorw("error fetching child device from core", log.Fields{"onuId": onuID})
1355 return err
1356 }
1357
1358 delTcontMsg := &ic.InterAdapterDeleteTcontMessage{UniId: uniID, TpPath: tpPath, AllocId: allocID}
1359 log.Debugw("sending tcont delete to openonu adapter", log.Fields{"msg": *delTcontMsg})
1360 if sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1361 delTcontMsg,
1362 ic.InterAdapterMessageType_DELETE_TCONT_REQUEST,
1363 f.deviceHandler.deviceType,
1364 onuDevice.Type,
1365 onuDevice.Id,
1366 onuDevice.ProxyAddress.DeviceId, ""); sendErr != nil {
1367 log.Errorw("failure sending del tcont to onu adapter", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1368 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1369 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1370 return sendErr
1371 }
1372 log.Debugw("success sending del tcont to onu adapter", log.Fields{"msg": delTcontMsg})
1373 return nil
1374}
1375
Girish Gowdra3d633032019-12-10 16:37:05 +05301376func (f *OpenOltFlowMgr) deletePendingFlows(Intf uint32, onuID int32, uniID int32) {
1377 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1378 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); ok {
1379 if val.(int) > 0 {
1380 pnFlDels := val.(int) - 1
1381 if pnFlDels > 0 {
1382 log.Debugw("flow delete succeeded, more pending",
1383 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1384 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1385 } else {
1386 log.Debugw("all pending flow deletes handled, removing entry from map",
1387 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1388 f.pendingFlowDelete.Delete(pnFlDelKey)
1389 }
1390 }
1391 } else {
1392 log.Debugw("no pending delete flows found",
1393 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1394
1395 }
1396
1397}
1398
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301399//clearResources clears pon resources in kv store and the device
1400func (f *OpenOltFlowMgr) clearResources(flow *ofp.OfpFlowStats, Intf uint32, onuID int32, uniID int32,
1401 gemPortID int32, flowID uint32, flowDirection string,
1402 portNum uint32, updatedFlows []rsrcMgr.FlowInfo) error {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001403
Chaitrashree G S90a17952019-11-14 21:51:21 -05001404 tpID, err := getTpIDFromFlow(flow)
1405 if err != nil {
1406 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID})
1407 return err
1408 }
Gamze Abakafee36392019-10-03 11:17:24 +00001409
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001410 if len(updatedFlows) >= 0 {
1411 // There are still flows referencing the same flow_id.
1412 // So the flow should not be freed yet.
1413 // For ex: Case of HSIA where same flow is shared
1414 // between DS and US.
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301415 f.updateFlowInfoToKVStore(int32(Intf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001416 if len(updatedFlows) == 0 {
Girish Gowdra3d633032019-12-10 16:37:05 +05301417 // Do this for subscriber flows only (not trap from NNI flows)
1418 if onuID != -1 && uniID != -1 {
1419 pnFlDelKey := pendingFlowDeleteKey{Intf, uint32(onuID), uint32(uniID)}
1420 if val, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1421 log.Debugw("creating entry for pending flow delete",
1422 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID})
1423 f.pendingFlowDelete.Store(pnFlDelKey, 1)
1424 } else {
1425 pnFlDels := val.(int) + 1
1426 log.Debugw("updating flow delete entry",
1427 log.Fields{"intf": Intf, "onuID": onuID, "uniID": uniID, "currPendingFlowCnt": pnFlDels})
1428 f.pendingFlowDelete.Store(pnFlDelKey, pnFlDels)
1429 }
1430
1431 defer f.deletePendingFlows(Intf, onuID, uniID)
1432 }
1433
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301434 log.Debugw("Releasing flow Id to resource manager", log.Fields{"Intf": Intf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
1435 f.resourceMgr.FreeFlowID(Intf, int32(onuID), int32(uniID), flowID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001436
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301437 uni := getUniPortPath(Intf, onuID, uniID)
1438 tpPath := f.getTPpath(Intf, uni, tpID)
Gamze Abakafee36392019-10-03 11:17:24 +00001439 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301440 techprofileInst, err := f.techprofile[Intf].GetTPInstanceFromKVStore(tpID, tpPath)
Gamze Abakafee36392019-10-03 11:17:24 +00001441 if err != nil { // This should not happen, something wrong in KV backend transaction
1442 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301443 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001444 }
1445 if techprofileInst == nil {
1446 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301447 return err
Gamze Abakafee36392019-10-03 11:17:24 +00001448 }
1449
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301450 gemPK := gemPortKey{Intf, uint32(gemPortID)}
Gamze Abakafee36392019-10-03 11:17:24 +00001451 if f.isGemPortUsedByAnotherFlow(gemPK) {
1452 flowIDs := f.flowsUsedByGemPort[gemPK]
1453 for i, flowIDinMap := range flowIDs {
1454 if flowIDinMap == flowID {
1455 flowIDs = append(flowIDs[:i], flowIDs[i+1:]...)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301456 // everytime flowsUsedByGemPort cache is updated the same should be updated
1457 // in kv store by calling UpdateFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001458 f.flowsUsedByGemPort[gemPK] = flowIDs
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301459 f.resourceMgr.UpdateFlowIDsForGem(Intf, uint32(gemPortID), flowIDs)
Gamze Abakafee36392019-10-03 11:17:24 +00001460 break
1461 }
1462 }
1463 log.Debugw("Gem port id is still used by other flows", log.Fields{"gemPortID": gemPortID, "usedByFlows": flowIDs})
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301464 return nil
Gamze Abakafee36392019-10-03 11:17:24 +00001465 }
Gamze Abakafee36392019-10-03 11:17:24 +00001466 log.Debugf("Gem port id %d is not used by another flow - releasing the gem port", gemPortID)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301467 f.resourceMgr.RemoveGemPortIDForOnu(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001468 // TODO: The TrafficQueue corresponding to this gem-port also should be removed immediately.
1469 // But it is anyway eventually removed later when the TechProfile is freed, so not a big issue for now.
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301470 f.resourceMgr.RemoveGEMportPonportToOnuMapOnKVStore(uint32(gemPortID), Intf)
Gamze Abakafee36392019-10-03 11:17:24 +00001471 f.onuIdsLock.Lock()
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301472 //everytime an entry is deleted from flowsUsedByGemPort cache, the same should be updated in kv as well
1473 // by calling DeleteFlowIDsForGem
Gamze Abakafee36392019-10-03 11:17:24 +00001474 delete(f.flowsUsedByGemPort, gemPK)
Abhilash Laxmeshwar275c0742019-11-25 16:47:02 +05301475 f.resourceMgr.DeleteFlowIDsForGem(Intf, uint32(gemPortID))
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301476 f.resourceMgr.FreeGemPortID(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001477 f.onuIdsLock.Unlock()
Girish Gowdra6b130582019-11-20 16:45:20 +05301478 // Delete the gem port on the ONU.
1479 if err := f.sendDeleteGemPortToChild(Intf, uint32(onuID), uint32(uniID), uint32(gemPortID), tpPath); err != nil {
1480 log.Errorw("error processing delete gem-port towards onu",
1481 log.Fields{"err": err, "pon": Intf, "onuID": onuID, "uniID": uniID, "gemPortId": gemPortID})
1482 }
Gamze Abakafee36392019-10-03 11:17:24 +00001483
Girish Gowdra54934262019-11-13 14:19:55 +05301484 ok, _ := f.isTechProfileUsedByAnotherGem(Intf, uint32(onuID), uint32(uniID), tpID, techprofileInst, uint32(gemPortID))
Gamze Abakafee36392019-10-03 11:17:24 +00001485 if !ok {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301486 f.resourceMgr.RemoveTechProfileIDForOnu(Intf, uint32(onuID), uint32(uniID), tpID)
1487 f.RemoveSchedulerQueues(schedQueue{direction: tp_pb.Direction_UPSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1488 f.RemoveSchedulerQueues(schedQueue{direction: tp_pb.Direction_DOWNSTREAM, intfID: Intf, onuID: uint32(onuID), uniID: uint32(uniID), tpID: tpID, uniPort: portNum, tpInst: techprofileInst})
1489 f.DeleteTechProfileInstance(Intf, uint32(onuID), uint32(uniID), "", tpID)
1490 f.resourceMgr.FreeAllocID(Intf, uint32(onuID), uint32(uniID), techprofileInst.UsScheduler.AllocID)
Girish Gowdra6b130582019-11-20 16:45:20 +05301491 // Delete the TCONT on the ONU.
1492 if err := f.sendDeleteTcontToChild(Intf, uint32(onuID), uint32(uniID), uint32(techprofileInst.UsScheduler.AllocID), tpPath); err != nil {
1493 log.Errorw("error processing delete tcont towards onu",
1494 log.Fields{"pon": Intf, "onuID": onuID, "uniID": uniID, "allocId": techprofileInst.UsScheduler.AllocID})
1495 }
Gamze Abakafee36392019-10-03 11:17:24 +00001496 }
1497 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001498 }
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301499 return nil
1500}
1501
1502func (f *OpenOltFlowMgr) clearFlowFromResourceManager(flow *ofp.OfpFlowStats, flowDirection string) {
1503
1504 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowDirection": flowDirection, "flow": *flow})
1505 var updatedFlows []rsrcMgr.FlowInfo
1506 var flowID uint32
1507 var onuID, uniID int32
1508 classifierInfo := make(map[string]interface{})
1509
1510 portNum, Intf, onu, uni, inPort, ethType, err := FlowExtractInfo(flow, flowDirection)
1511 if err != nil {
1512 log.Error(err)
1513 return
1514 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301515
Abhilash Laxmeshwarb7300fe2019-11-13 03:38:33 +05301516 onuID = int32(onu)
1517 uniID = int32(uni)
1518
1519 for _, field := range flows.GetOfbFields(flow) {
1520 if field.Type == flows.IP_PROTO {
1521 classifierInfo[IPProto] = field.GetIpProto()
1522 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1523 }
1524 }
1525 log.Debugw("Extracted access info from flow to be deleted",
1526 log.Fields{"ponIntf": Intf, "onuID": onuID, "uniID": uniID})
1527
1528 if ethType == LldpEthType || ((classifierInfo[IPProto] == IPProtoDhcp) && (flowDirection == "downstream")) {
1529 onuID = -1
1530 uniID = -1
1531 log.Debug("Trap on nni flow set oni, uni to -1")
1532 Intf = IntfIDFromNniPortNum(inPort)
1533 }
1534 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(Intf, onuID, uniID)
1535 for _, flowID = range flowIds {
1536 flowInfo := f.resourceMgr.GetFlowIDInfo(Intf, onuID, uniID, flowID)
1537 if flowInfo == nil {
1538 log.Debugw("No FlowInfo found found in KV store",
1539 log.Fields{"Intf": Intf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
1540 return
1541 }
1542 updatedFlows = nil
1543 for _, flow := range *flowInfo {
1544 updatedFlows = append(updatedFlows, flow)
1545 }
1546
1547 for i, storedFlow := range updatedFlows {
1548 if flow.Id == storedFlow.LogicalFlowID {
1549 removeFlowMessage := openoltpb2.Flow{FlowId: storedFlow.Flow.FlowId, FlowType: storedFlow.Flow.FlowType}
1550 log.Debugw("Flow to be deleted", log.Fields{"flow": storedFlow})
1551 if ok := f.removeFlowFromDevice(&removeFlowMessage); ok {
1552 log.Debug("Flow removed from device successfully")
1553 //Remove the Flow from FlowInfo
1554 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1555 err = f.clearResources(flow, Intf, onuID, uniID, storedFlow.Flow.GemportId,
1556 flowID, flowDirection, portNum, updatedFlows)
1557 if err != nil {
1558 log.Error("Failed to clear resources for flow", log.Fields{"flow": storedFlow})
1559 return
1560 }
1561 } else {
1562 log.Error("Failed to remove flow from device")
1563 return
1564 }
1565 }
1566 }
1567 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001568}
1569
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001570//RemoveFlow removes the flow from the device
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001571func (f *OpenOltFlowMgr) RemoveFlow(flow *ofp.OfpFlowStats) {
1572 log.Debugw("Removing Flow", log.Fields{"flow": flow})
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301573 var direction string
1574 actionInfo := make(map[string]interface{})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001575
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301576 for _, action := range flows.GetActions(flow) {
1577 if action.Type == flows.OUTPUT {
1578 if out := action.GetOutput(); out != nil {
1579 actionInfo[Output] = out.GetPort()
1580 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
1581 } else {
1582 log.Error("Invalid output port in action")
1583 return
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001584 }
1585 }
1586 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301587 if IsUpstream(actionInfo[Output].(uint32)) {
1588 direction = Upstream
1589 } else {
1590 direction = Downstream
1591 }
1592
1593 f.clearFlowFromResourceManager(flow, direction) //TODO: Take care of the limitations
1594
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001595 return
1596}
1597
Girish Gowdra3d633032019-12-10 16:37:05 +05301598func (f *OpenOltFlowMgr) waitForFlowDeletesToCompleteForOnu(ctx context.Context, intfID uint32, onuID uint32,
1599 uniID uint32, ch chan bool) {
1600 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1601 for {
1602 select {
1603 case <-time.After(20 * time.Millisecond):
1604 if flowDelRefCnt, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok || flowDelRefCnt == 0 {
1605 log.Debug("pending flow deletes completed")
1606 ch <- true
1607 return
1608 }
1609 case <-ctx.Done():
1610 log.Error("flow delete wait handler routine canceled")
1611 return
1612 }
1613 }
1614}
1615
Esin Karamanae41e2b2019-12-17 18:13:13 +00001616//isIgmpTrapDownstreamFlow return true if the flow is a downsteam IGMP trap-to-host flow; false otherwise
1617func isIgmpTrapDownstreamFlow(classifierInfo map[string]interface{}) bool {
1618 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_ETHERNET_NNI {
1619 if ethType, ok := classifierInfo[EthType]; ok {
1620 if ethType.(uint32) == IPv4EthType {
1621 if ipProto, ok := classifierInfo[IPProto]; ok {
1622 if ipProto.(uint32) == IgmpProto {
1623 return true
1624 }
1625 }
1626 }
1627 }
1628 }
1629 return false
1630}
1631
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001632// AddFlow add flow to device
Manikkaraj kb1d51442019-07-23 10:41:02 -04001633func (f *OpenOltFlowMgr) AddFlow(flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001634 classifierInfo := make(map[string]interface{})
1635 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001636 var UsMeterID uint32
1637 var DsMeterID uint32
1638
1639 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
salmansiddiqui7ac62132019-08-22 03:58:50 +00001640 formulateClassifierInfoFromFlow(classifierInfo, flow)
1641
1642 err := formulateActionInfoFromFlow(actionInfo, classifierInfo, flow)
1643 if err != nil {
1644 // Error logging is already done in the called function
1645 // So just return in case of error
1646 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301647 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001648
manikkaraj k17652a72019-05-06 09:06:36 -04001649 /* Controller bound trap flows */
salmansiddiqui7ac62132019-08-22 03:58:50 +00001650 err = formulateControllerBoundTrapFlowInfo(actionInfo, classifierInfo, flow)
1651 if err != nil {
1652 // error if any, already logged in the called function
1653 return
manikkaraj k17652a72019-05-06 09:06:36 -04001654 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001655
David K. Bainbridge82efc492019-09-04 09:57:11 -07001656 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[Output]})
1657 portNo, intfID, onuID, uniID := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[Output].(uint32))
A R Karthick1f85b802019-10-11 05:06:05 +00001658
Humera Kouser94d7a842019-08-25 19:04:32 -04001659 if ethType, ok := classifierInfo[EthType]; ok {
1660 if ethType.(uint32) == LldpEthType {
1661 log.Info("Adding LLDP flow")
1662 f.addLLDPFlow(flow, portNo)
1663 return
1664 }
1665 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001666 if ipProto, ok := classifierInfo[IPProto]; ok {
1667 if ipProto.(uint32) == IPProtoDhcp {
1668 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001669 if udpSrc.(uint32) == uint32(67) {
1670 log.Debug("trap-dhcp-from-nni-flow")
1671 f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
1672 return
1673 }
1674 }
1675 }
1676 }
Esin Karamanae41e2b2019-12-17 18:13:13 +00001677 if isIgmpTrapDownstreamFlow(classifierInfo) {
1678 log.Debug("trap-igmp-from-nni-flow")
1679 f.addIgmpTrapFlowOnNNI(flow, classifierInfo, portNo)
1680 return
1681 }
A R Karthick1f85b802019-10-11 05:06:05 +00001682
1683 f.deviceHandler.AddUniPortToOnu(intfID, onuID, portNo)
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301684 f.resourceMgr.AddUniPortToOnuInfo(intfID, onuID, portNo)
A R Karthick1f85b802019-10-11 05:06:05 +00001685
Chaitrashree G S90a17952019-11-14 21:51:21 -05001686 TpID, err := getTpIDFromFlow(flow)
1687 if err != nil {
1688 log.Error("metadata-is-not-present-invalid-flow-to-process", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1689 return
1690 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00001691 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfID, "onuID": onuID, "uniID": uniID})
David K. Bainbridge82efc492019-09-04 09:57:11 -07001692 if IsUpstream(actionInfo[Output].(uint32)) {
Scott Baker355d1742019-10-24 10:57:52 -07001693 UsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001694 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1695 } else {
Scott Baker355d1742019-10-24 10:57:52 -07001696 DsMeterID = flows.GetMeterIdFromFlow(flow)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001697 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1698
1699 }
Girish Gowdra3d633032019-12-10 16:37:05 +05301700
1701 pnFlDelKey := pendingFlowDeleteKey{intfID, onuID, uniID}
1702 if _, ok := f.pendingFlowDelete.Load(pnFlDelKey); !ok {
1703 log.Debugw("no pending flows found, going ahead with flow install", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1704 f.divideAndAddFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
1705 } else {
1706 ctx := context.Background()
1707 ctx, cancel := context.WithCancel(ctx)
1708 defer cancel()
1709 pendingFlowDelComplete := make(chan bool)
1710 go f.waitForFlowDeletesToCompleteForOnu(ctx, intfID, onuID, uniID, pendingFlowDelComplete)
1711 select {
1712 case <-pendingFlowDelComplete:
1713 log.Debugw("all pending flow deletes completed", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1714 f.divideAndAddFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
1715
1716 case <-time.After(10 * time.Second):
1717 log.Errorw("pending flow deletes not completed after timeout", log.Fields{"pon": intfID, "onuID": onuID, "uniID": uniID})
1718 }
1719 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001720}
1721
1722//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04001723func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001724
1725 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301726 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001727 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301728 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05301729 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301730 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04001731
Manikkaraj kb1d51442019-07-23 10:41:02 -04001732 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001733 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04001734 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
1735 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1736 tpDownloadMsg,
1737 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
1738 f.deviceHandler.deviceType,
1739 onuDevice.Type,
1740 onuDevice.Id,
1741 onuDevice.ProxyAddress.DeviceId, "")
1742 if sendErr != nil {
1743 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1744 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1745 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1746 return sendErr
1747 }
1748 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05301749 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301750}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001751
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301752//UpdateOnuInfo function adds onu info to cache and kvstore
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001753func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301754
1755 f.lockCache.Lock()
1756 defer f.lockCache.Unlock()
1757 onu := rsrcMgr.OnuGemInfo{OnuID: onuID, SerialNumber: serialNum, IntfID: intfID}
1758 f.onuGemInfo[intfID] = append(f.onuGemInfo[intfID], onu)
1759 if err := f.resourceMgr.AddOnuInfo(intfID, onu); err != nil {
1760 log.Errorw("failed to add onu info", log.Fields{"onu": onu})
1761 return
1762 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001763 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
1764}
1765
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301766//addGemPortToOnuInfoMap function adds GEMport to ONU map
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001767func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfID uint32, onuID uint32, gemPort uint32) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301768 f.lockCache.Lock()
1769 defer f.lockCache.Unlock()
1770 onugem := f.onuGemInfo[intfID]
1771 // update the gem to the local cache as well as to kv strore
1772 for idx, onu := range onugem {
1773 if onu.OnuID == onuID {
1774 // check if gem already exists , else update the cache and kvstore
1775 for _, gem := range onu.GemPorts {
1776 if gem == gemPort {
1777 log.Debugw("Gem already in cache, no need to update cache and kv store",
1778 log.Fields{"gem": gemPort})
1779 return
1780 }
1781 }
1782 onugem[idx].GemPorts = append(onugem[idx].GemPorts, gemPort)
1783 f.onuGemInfo[intfID] = onugem
1784 }
1785 }
1786 err := f.resourceMgr.AddGemToOnuGemInfo(intfID, onuID, gemPort)
1787 if err != nil {
1788 log.Errorw("Failed to add gem to onu", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001789 return
1790 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001791}
1792
1793// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001794
1795//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
1796func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301797
1798 f.lockCache.Lock()
1799 defer f.lockCache.Unlock()
1800
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001801 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 +05301802 // get onuid from the onugem info cache
1803 onugem := f.onuGemInfo[intfID]
1804 for _, onu := range onugem {
1805 for _, gem := range onu.GemPorts {
1806 if gem == gemPortID {
1807 return onu.OnuID, nil
1808 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001809 }
1810 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001811 log.Errorw("onuid is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPort": gemPortID})
1812 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 -04001813}
1814
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001815//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
1816func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001817 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001818 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001819 var err error
1820
1821 if packetIn.IntfType == "pon" {
1822 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001823 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001824 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
1825 return logicalPortNum, err
1826 }
1827 if packetIn.PortNo != 0 {
1828 logicalPortNum = packetIn.PortNo
1829 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001830 uniID := uint32(0) // FIXME - multi-uni support
1831 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001832 }
1833 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301834 f.UpdateGemPortForPktIn(packetIn.IntfId, onuID, logicalPortNum, packetIn.GemportId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001835 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001836 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001837 }
Matteo Scandolo6056e822019-11-13 14:05:29 -08001838 log.Debugw("Retrieved logicalport from packet-in", log.Fields{
1839 "logicalPortNum": logicalPortNum,
1840 "IntfType": packetIn.IntfType,
1841 "packet": hex.EncodeToString(packetIn.Pkt),
1842 })
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001843 return logicalPortNum, nil
1844}
1845
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001846//GetPacketOutGemPortID returns gemPortId
1847func (f *OpenOltFlowMgr) GetPacketOutGemPortID(intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
1848 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001849 var err error
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301850
1851 f.lockCache.Lock()
1852 defer f.lockCache.Unlock()
1853 pktInkey := rsrcMgr.PacketInInfoKey{IntfID: intfID, OnuID: onuID, LogicalPort: portNum}
1854
1855 gemPortID, ok := f.packetInGemPort[pktInkey]
1856 if ok {
1857 log.Debugw("Found gemport for pktin key", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
1858 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001859 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301860 //If gem is not found in cache try to get it from kv store, if found in kv store, update the cache and return.
1861 gemPortID, err = f.resourceMgr.GetGemPortFromOnuPktIn(intfID, onuID, portNum)
1862 if err == nil {
1863 if gemPortID != 0 {
1864 f.packetInGemPort[pktInkey] = gemPortID
1865 log.Debugw("Found gem port from kv store and updating cache with gemport",
1866 log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
1867 return gemPortID, nil
1868 }
1869 }
1870 log.Errorw("Failed to get gemport", log.Fields{"pktinkey": pktInkey, "gem": gemPortID})
1871 return uint32(0), err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001872}
1873
Manikkaraj kb1d51442019-07-23 10:41:02 -04001874func installFlowOnAllGemports(
1875 f1 func(intfId uint32, onuId uint32, uniId uint32,
1876 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
1877 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32),
1878 f2 func(intfId uint32, onuId uint32, uniId uint32, portNo uint32,
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301879 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32,
1880 classifier map[string]interface{}, action map[string]interface{}),
Manikkaraj kb1d51442019-07-23 10:41:02 -04001881 args map[string]uint32,
1882 classifier map[string]interface{}, action map[string]interface{},
1883 logicalFlow *ofp.OfpFlowStats,
1884 gemPorts []uint32,
1885 FlowType string,
salmansiddiqui7ac62132019-08-22 03:58:50 +00001886 vlanID ...uint32) {
1887 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanID})
1888 for _, gemPortID := range gemPorts {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001889 if FlowType == HsiaFlow || FlowType == DhcpFlow {
salmansiddiqui7ac62132019-08-22 03:58:50 +00001890 f1(args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001891 } else if FlowType == EapolFlow {
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301892 f2(args["intfId"], args["onuId"], args["uniId"], args["portNo"], logicalFlow, args["allocId"], gemPortID, vlanID[0], classifier, action)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001893 } else {
1894 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
1895 return
1896 }
1897 }
1898}
1899
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001900func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
1901 log.Debug("Adding trap-dhcp-of-nni-flow")
1902 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001903 classifier[PacketTagType] = DoubleTag
1904 action[TrapToHost] = true
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301905 var err error
1906 var networkInterfaceID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001907 /* We manage flowId resource pool on per PON port basis.
1908 Since this situation is tricky, as a hack, we pass the NNI port
1909 index (network_intf_id) as PON port Index for the flowId resource
1910 pool. Also, there is no ONU Id available for trapping DHCP packets
1911 on NNI port, use onu_id as -1 (invalid)
1912 ****************** CAVEAT *******************
1913 This logic works if the NNI Port Id falls within the same valid
1914 range of PON Port Ids. If this doesn't work for some OLT Vendor
1915 we need to have a re-look at this.
1916 *********************************************
1917 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001918 onuID := -1
1919 uniID := -1
1920 gemPortID := -1
1921 allocID := -1
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301922 networkInterfaceID, err = getNniIntfID(classifier, action)
1923 if err != nil {
1924 log.Error("Failed to get nniIntf ID")
1925 return
1926 }
1927
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001928 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301929 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001930 log.Debug("Flow-exists--not-re-adding")
1931 return
1932 }
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301933 flowID, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001934 if err != nil {
1935 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
1936 return
1937 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001938 var classifierProto *openoltpb2.Classifier
1939 var actionProto *openoltpb2.Action
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001940 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
1941 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
1942 return
1943 }
1944 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1945 if actionProto = makeOpenOltActionField(action); actionProto == nil {
1946 log.Error("Error in making action protobuf for dhcp trap on nni flow")
1947 return
1948 }
1949 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001950 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1951 OnuId: int32(onuID), // OnuId not required
1952 UniId: int32(uniID), // UniId not used
1953 FlowId: flowID,
David K. Bainbridge82efc492019-09-04 09:57:11 -07001954 FlowType: Downstream,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001955 AllocId: int32(allocID), // AllocId not used
1956 NetworkIntfId: int32(networkInterfaceID),
1957 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001958 Classifier: classifierProto,
1959 Action: actionProto,
1960 Priority: int32(logicalFlow.Priority),
1961 Cookie: logicalFlow.Cookie,
1962 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001963 if ok := f.addFlowToDevice(logicalFlow, &downstreamflow); ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001964 log.Debug("DHCP trap on NNI flow added to device successfully")
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05301965 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001966 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceID),
1967 int32(onuID),
1968 int32(uniID),
1969 flowID, flowsToKVStore); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001970 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1971 }
1972 }
1973 return
1974}
salmansiddiqui7ac62132019-08-22 03:58:50 +00001975
Esin Karamanae41e2b2019-12-17 18:13:13 +00001976//getPacketTypeFromClassifiers finds and returns packet type of a flow by checking flow classifiers
1977func getPacketTypeFromClassifiers(classifierInfo map[string]interface{}) string {
1978 var packetType string
1979 ovid, ivid := false, false
1980 if vlanID, ok := classifierInfo[VlanVid].(uint32); ok {
1981 vid := vlanID & VlanvIDMask
1982 if vid != ReservedVlan {
1983 ovid = true
1984 }
1985 }
1986 if metadata, ok := classifierInfo[Metadata].(uint64); ok {
1987 vid := uint32(metadata)
1988 if vid != ReservedVlan {
1989 ivid = true
1990 }
1991 }
1992 if ovid && ivid {
1993 packetType = DoubleTag
1994 } else if !ovid && !ivid {
1995 packetType = Untagged
1996 } else {
1997 packetType = SingleTag
1998 }
1999 return packetType
2000}
2001
2002//addIgmpTrapFlowOnNNI adds a trap-to-host flow on NNI
2003func (f *OpenOltFlowMgr) addIgmpTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
2004 log.Debugw("Adding igmp-trap-of-nni-flow", log.Fields{"classifierInfo": classifier})
2005 action := make(map[string]interface{})
2006 classifier[PacketTagType] = getPacketTypeFromClassifiers(classifier)
2007 action[TrapToHost] = true
2008 /* We manage flowId resource pool on per PON port basis.
2009 Since this situation is tricky, as a hack, we pass the NNI port
2010 index (network_intf_id) as PON port Index for the flowId resource
2011 pool. Also, there is no ONU Id available for trapping packets
2012 on NNI port, use onu_id as -1 (invalid)
2013 ****************** CAVEAT *******************
2014 This logic works if the NNI Port Id falls within the same valid
2015 range of PON Port Ids. If this doesn't work for some OLT Vendor
2016 we need to have a re-look at this.
2017 *********************************************
2018 */
2019 onuID := -1
2020 uniID := -1
2021 gemPortID := -1
2022 allocID := -1
2023 networkInterfaceID, err := getNniIntfID(classifier, action)
2024 if err != nil {
2025 log.Error("Failed to get nniIntf ID")
2026 return
2027 }
2028 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
2029 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceID), int32(onuID), int32(uniID), flowStoreCookie); present {
2030 log.Debug("igmp-flow-exists--not-re-adding")
2031 return
2032 }
2033 flowID, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceID), int32(onuID), int32(uniID), uint32(gemPortID), flowStoreCookie, "", 0, 0)
2034 if err != nil {
2035 log.Errorw("IGMP flow id unavailable for trap-on-NNI flow", log.Fields{"error": err})
2036 return
2037 }
2038 var classifierProto *openoltpb2.Classifier
2039 var actionProto *openoltpb2.Action
2040 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
2041 log.Error("Error in making classifier protobuf for igmp trap on nni flow")
2042 return
2043 }
2044 log.Debugw("Created classifier proto for the IGMP flow", log.Fields{"classifier": *classifierProto})
2045 if actionProto = makeOpenOltActionField(action); actionProto == nil {
2046 log.Error("Error in making action protobuf for IGMP trap on nni flow")
2047 return
2048 }
2049 log.Debugw("Created action proto for the IGMP flow", log.Fields{"action": *actionProto})
2050 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
2051 OnuId: int32(onuID), // OnuId not required
2052 UniId: int32(uniID), // UniId not used
2053 FlowId: flowID,
2054 FlowType: Downstream,
2055 AllocId: int32(allocID), // AllocId not used
2056 NetworkIntfId: int32(networkInterfaceID),
2057 GemportId: int32(gemPortID), // GemportId not used
2058 Classifier: classifierProto,
2059 Action: actionProto,
2060 Priority: int32(logicalFlow.Priority),
2061 Cookie: logicalFlow.Cookie,
2062 PortNo: portNo}
2063 if ok := f.addFlowToDevice(logicalFlow, &downstreamflow); ok {
2064 log.Debug("IGMP Trap on NNI flow added to device successfully")
2065 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowID, logicalFlow.Id)
2066 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceID),
2067 int32(onuID),
2068 int32(uniID),
2069 flowID, flowsToKVStore); err != nil {
2070 log.Errorw("Error uploading igmp-trap-on-nni flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
2071 }
2072 }
2073 return
2074}
2075
salmansiddiqui7ac62132019-08-22 03:58:50 +00002076func verifyMeterIDAndGetDirection(MeterID uint32, Dir tp_pb.Direction) (string, error) {
2077 if MeterID == 0 { // This should never happen
2078 log.Error("Invalid meter id")
2079 return "", errors.New("invalid meter id")
2080 }
2081 if Dir == tp_pb.Direction_UPSTREAM {
2082 return "upstream", nil
2083 } else if Dir == tp_pb.Direction_DOWNSTREAM {
2084 return "downstream", nil
2085 }
2086 return "", nil
2087}
2088
2089func (f *OpenOltFlowMgr) checkAndAddFlow(args map[string]uint32, classifierInfo map[string]interface{},
Gamze Abakafee36392019-10-03 11:17:24 +00002090 actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpInst *tp.TechProfile, gemPorts []uint32,
2091 TpID uint32, uni string) {
2092 var gemPort uint32
2093 intfID := args[IntfID]
2094 onuID := args[OnuID]
2095 uniID := args[UniID]
2096 portNo := args[PortNo]
2097 allocID := TpInst.UsScheduler.AllocID
salmansiddiqui7ac62132019-08-22 03:58:50 +00002098 if ipProto, ok := classifierInfo[IPProto]; ok {
2099 if ipProto.(uint32) == IPProtoDhcp {
2100 log.Info("Adding DHCP flow")
2101 if pcp, ok := classifierInfo[VlanPcp]; ok {
2102 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2103 tp_pb.Direction_UPSTREAM,
2104 pcp.(uint32))
2105 //Adding DHCP upstream flow
Gamze Abakafee36392019-10-03 11:17:24 +00002106 f.addDHCPTrapFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002107 } else {
2108 //Adding DHCP upstream flow to all gemports
2109 installFlowOnAllGemports(f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
2110 }
2111
2112 } else if ipProto == IgmpProto {
Esin Karamanae41e2b2019-12-17 18:13:13 +00002113 log.Infow("Adding Us IGMP flow", log.Fields{"intfID": intfID, "onuID": onuID, "uniID": uniID, "classifierInfo:": classifierInfo})
2114 if pcp, ok := classifierInfo[VlanPcp]; ok {
2115 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2116 tp_pb.Direction_UPSTREAM,
2117 pcp.(uint32))
2118 f.addIGMPTrapFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
2119 } else {
2120 //Adding IGMP upstream flow to all gem ports
2121 installFlowOnAllGemports(f.addIGMPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, IgmpFlow)
2122 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002123 } else {
2124 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
2125 return
2126 }
2127 } else if ethType, ok := classifierInfo[EthType]; ok {
2128 if ethType.(uint32) == EapEthType {
2129 log.Info("Adding EAPOL flow")
2130 var vlanID uint32
2131 if val, ok := classifierInfo[VlanVid]; ok {
2132 vlanID = (val.(uint32)) & VlanvIDMask
2133 } else {
2134 vlanID = DefaultMgmtVlan
2135 }
2136 if pcp, ok := classifierInfo[VlanPcp]; ok {
2137 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2138 tp_pb.Direction_UPSTREAM,
2139 pcp.(uint32))
2140
Abhilash Laxmeshwarab0bd522019-10-21 15:05:15 +05302141 f.addEAPOLFlow(intfID, onuID, uniID, portNo, flow, allocID, gemPort, vlanID, classifierInfo, actionInfo)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002142 } else {
2143 installFlowOnAllGemports(nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanID)
2144 }
2145 }
salmansiddiqui7ac62132019-08-22 03:58:50 +00002146 } else if _, ok := actionInfo[PushVlan]; ok {
2147 log.Info("Adding upstream data rule")
2148 if pcp, ok := classifierInfo[VlanPcp]; ok {
2149 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
2150 tp_pb.Direction_UPSTREAM,
2151 pcp.(uint32))
2152 //Adding HSIA upstream flow
Gamze Abakafee36392019-10-03 11:17:24 +00002153 f.addUpstreamDataFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002154 } else {
2155 //Adding HSIA upstream flow to all gemports
2156 installFlowOnAllGemports(f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
2157 }
2158 } else if _, ok := actionInfo[PopVlan]; ok {
2159 log.Info("Adding Downstream data rule")
2160 if pcp, ok := classifierInfo[VlanPcp]; ok {
2161 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
aishwaryarana01d9f985f2019-09-03 15:41:40 -05002162 tp_pb.Direction_DOWNSTREAM,
salmansiddiqui7ac62132019-08-22 03:58:50 +00002163 pcp.(uint32))
2164 //Adding HSIA downstream flow
Gamze Abakafee36392019-10-03 11:17:24 +00002165 f.addDownstreamDataFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocID, gemPort)
salmansiddiqui7ac62132019-08-22 03:58:50 +00002166 } else {
2167 //Adding HSIA downstream flow to all gemports
2168 installFlowOnAllGemports(f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
2169 }
2170 } else {
2171 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
2172 return
2173 }
2174 // Send Techprofile download event to child device in go routine as it takes time
2175 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpID)
2176}
2177
Gamze Abakafee36392019-10-03 11:17:24 +00002178func (f *OpenOltFlowMgr) isGemPortUsedByAnotherFlow(gemPK gemPortKey) bool {
2179 flowIDList := f.flowsUsedByGemPort[gemPK]
2180 if len(flowIDList) > 1 {
2181 return true
2182 }
2183 return false
2184}
2185
Girish Gowdra54934262019-11-13 14:19:55 +05302186func (f *OpenOltFlowMgr) isTechProfileUsedByAnotherGem(ponIntf uint32, onuID uint32, uniID uint32, tpID uint32, tpInst *tp.TechProfile, gemPortID uint32) (bool, uint32) {
Gamze Abakafee36392019-10-03 11:17:24 +00002187 currentGemPorts := f.resourceMgr.GetCurrentGEMPortIDsForOnu(ponIntf, onuID, uniID)
2188 tpGemPorts := tpInst.UpstreamGemPortAttributeList
2189 for _, currentGemPort := range currentGemPorts {
2190 for _, tpGemPort := range tpGemPorts {
2191 if (currentGemPort == tpGemPort.GemportID) && (currentGemPort != gemPortID) {
2192 return true, currentGemPort
2193 }
2194 }
2195 }
Girish Gowdra54934262019-11-13 14:19:55 +05302196 if tpInst.InstanceCtrl.Onu == "single-instance" {
2197 // The TP information for the given TP ID, PON ID, ONU ID, UNI ID should be removed.
2198 f.resourceMgr.RemoveTechProfileIDForOnu(ponIntf, uint32(onuID), uint32(uniID), tpID)
2199 f.DeleteTechProfileInstance(ponIntf, uint32(onuID), uint32(uniID), "", tpID)
2200
2201 // Although we cleaned up TP Instance for the given (PON ID, ONU ID, UNI ID), the TP might
2202 // still be used on other uni ports.
2203 // So, we need to check and make sure that no other gem port is referring to the given TP ID
2204 // on any other uni port.
2205 tpInstances := f.techprofile[ponIntf].FindAllTpInstances(tpID, ponIntf, onuID)
Girish Gowdra6b130582019-11-20 16:45:20 +05302206 log.Debugw("got single instance tp instances", log.Fields{"tpInstances": tpInstances})
Girish Gowdra54934262019-11-13 14:19:55 +05302207 for i := 0; i < len(tpInstances); i++ {
2208 tpI := tpInstances[i]
2209 tpGemPorts := tpI.UpstreamGemPortAttributeList
Girish Gowdra6b130582019-11-20 16:45:20 +05302210 for _, tpGemPort := range tpGemPorts {
2211 if tpGemPort.GemportID != gemPortID {
2212 log.Debugw("single instance tp is in use by gem", log.Fields{"gemPort": tpGemPort.GemportID})
2213 return true, tpGemPort.GemportID
Girish Gowdra54934262019-11-13 14:19:55 +05302214 }
2215 }
2216 }
2217 }
Girish Gowdra6b130582019-11-20 16:45:20 +05302218 log.Debug("tech profile is not in use by any gem")
Gamze Abakafee36392019-10-03 11:17:24 +00002219 return false, 0
2220}
2221
salmansiddiqui7ac62132019-08-22 03:58:50 +00002222func formulateClassifierInfoFromFlow(classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
Scott Baker355d1742019-10-24 10:57:52 -07002223 for _, field := range flows.GetOfbFields(flow) {
2224 if field.Type == flows.ETH_TYPE {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002225 classifierInfo[EthType] = field.GetEthType()
2226 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002227 } else if field.Type == flows.IP_PROTO {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002228 classifierInfo[IPProto] = field.GetIpProto()
2229 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002230 } else if field.Type == flows.IN_PORT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002231 classifierInfo[InPort] = field.GetPort()
2232 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002233 } else if field.Type == flows.VLAN_VID {
Girish Gowdra26f344b2019-10-23 14:39:13 +05302234 classifierInfo[VlanVid] = field.GetVlanVid() & 0xfff
salmansiddiqui7ac62132019-08-22 03:58:50 +00002235 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002236 } else if field.Type == flows.VLAN_PCP {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002237 classifierInfo[VlanPcp] = field.GetVlanPcp()
2238 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002239 } else if field.Type == flows.UDP_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002240 classifierInfo[UDPDst] = field.GetUdpDst()
2241 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002242 } else if field.Type == flows.UDP_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002243 classifierInfo[UDPSrc] = field.GetUdpSrc()
2244 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002245 } else if field.Type == flows.IPV4_DST {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002246 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
2247 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002248 } else if field.Type == flows.IPV4_SRC {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002249 classifierInfo[Ipv4Src] = field.GetIpv4Src()
2250 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
Scott Baker355d1742019-10-24 10:57:52 -07002251 } else if field.Type == flows.METADATA {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002252 classifierInfo[Metadata] = field.GetTableMetadata()
2253 log.Debug("field-type-metadata", log.Fields{"classifierInfo[Metadata]": classifierInfo[Metadata].(uint64)})
Scott Baker355d1742019-10-24 10:57:52 -07002254 } else if field.Type == flows.TUNNEL_ID {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002255 classifierInfo[TunnelID] = field.GetTunnelId()
2256 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
2257 } else {
2258 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
2259 return
2260 }
2261 }
2262}
2263
2264func formulateActionInfoFromFlow(actionInfo, classifierInfo map[string]interface{}, flow *ofp.OfpFlowStats) error {
Scott Baker355d1742019-10-24 10:57:52 -07002265 for _, action := range flows.GetActions(flow) {
2266 if action.Type == flows.OUTPUT {
salmansiddiqui7ac62132019-08-22 03:58:50 +00002267 if out := action.GetOutput(); out != nil {
David K. Bainbridge82efc492019-09-04 09:57:11 -07002268 actionInfo[Output] = out.GetPort()
2269 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[Output].(uint32)})
salmansiddiqui7ac6213