blob: 9917d82f66cd0747d6bc9658e5a44543561283dc [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"
23 "encoding/json"
24 "errors"
25 "fmt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040026 "math/big"
27
manikkaraj kbf256be2019-03-25 00:13:48 +053028 "github.com/opencord/voltha-go/common/log"
29 tp "github.com/opencord/voltha-go/common/techprofile"
Matt Jeannereta93dbed2019-05-17 12:40:05 -040030 "github.com/opencord/voltha-go/rw_core/utils"
Manikkaraj k884c1242019-04-11 16:26:42 +053031 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
manikkaraj k17652a72019-05-06 09:06:36 -040032 ic "github.com/opencord/voltha-protos/go/inter_container"
manikkaraj kbf256be2019-03-25 00:13:48 +053033 ofp "github.com/opencord/voltha-protos/go/openflow_13"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070034 openoltpb2 "github.com/opencord/voltha-protos/go/openolt"
Manikkaraj kb1d51442019-07-23 10:41:02 -040035 tp_pb "github.com/opencord/voltha-protos/go/tech_profile"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070036 "github.com/opencord/voltha-protos/go/voltha"
Chaitrashree G S230040a2019-08-20 20:50:47 -040037
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040038 //deepcopy "github.com/getlantern/deepcopy"
Daniele Rossi22db98e2019-07-11 11:50:00 +000039 "google.golang.org/grpc/codes"
40 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053041)
42
43const (
44 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053045
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070046 //HsiaFlow flow category
47 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053048
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070049 //EapolFlow flow category
50 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053051
Manikkaraj kb1d51442019-07-23 10:41:02 -040052 //DhcpFlow flow category
53 DhcpFlow = "DHCP_FLOW"
54
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070055 //IPProtoDhcp flow category
56 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053057
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070058 //IPProtoIgmp flow category
59 IPProtoIgmp = 2
60
61 //EapEthType eapethtype value
62 EapEthType = 0x888e
63 //LldpEthType lldp ethtype value
64 LldpEthType = 0x88cc
65
66 //IgmpProto proto value
67 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053068
69 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070070
Harsh Awasthie9644e02019-08-26 02:39:00 -040071 //Transparent Vlan
72 RESERVED_VLAN = 4095
73
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070074 //DefaultMgmtVlan default vlan value
75 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053076
manikkaraj kbf256be2019-03-25 00:13:48 +053077 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070078
79 //UPSTREAM constant
80 UPSTREAM = "upstream"
81 //DOWNSTREAM constant
82 DOWNSTREAM = "downstream"
83 //PacketTagType constant
84 PacketTagType = "pkt_tag_type"
85 //UNTAGGED constant
86 UNTAGGED = "untagged"
87 //SingleTag constant
88 SingleTag = "single_tag"
89 //DoubleTag constant
90 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +053091
92 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070093
94 //EthType constant
95 EthType = "eth_type"
96 //TPID constant
97 TPID = "tpid"
98 //IPProto constant
99 IPProto = "ip_proto"
100 //InPort constant
101 InPort = "in_port"
102 //VlanVid constant
103 VlanVid = "vlan_vid"
104 //VlanPcp constant
105 VlanPcp = "vlan_pcp"
106
107 //UDPDst constant
108 UDPDst = "udp_dst"
109 //UDPSrc constant
110 UDPSrc = "udp_src"
111 //Ipv4Dst constant
112 Ipv4Dst = "ipv4_dst"
113 //Ipv4Src constant
114 Ipv4Src = "ipv4_src"
115 //METADATA constant
116 METADATA = "metadata"
117 //TunnelID constant
118 TunnelID = "tunnel_id"
119 //OUTPUT constant
120 OUTPUT = "output"
121 // Actions
122
123 //PopVlan constant
124 PopVlan = "pop_vlan"
125 //PushVlan constant
126 PushVlan = "push_vlan"
127 //TrapToHost constant
128 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400129 //MaxMeterBand constant
130 MaxMeterBand = 2
131 //VlanPCPMask contant
132 VlanPCPMask = 0xFF
133 //VlanvIDMask constant
134 VlanvIDMask = 0xFFF
135 //MaxPonPorts constant
136 MaxPonPorts = 16
manikkaraj kbf256be2019-03-25 00:13:48 +0530137)
138
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400139type onuInfo struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700140 intfID uint32
141 onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400142 serialNumber string
143}
144
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700145type onuIDKey struct {
146 intfID uint32
147 onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400148}
149
150type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700151 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400152 gemPort uint32
153}
154
155type packetInInfoKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700156 intfID uint32
157 onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400158 logicalPort uint32
159}
160
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700161//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530162type OpenOltFlowMgr struct {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400163 techprofile []*tp.TechProfileMgr
164 deviceHandler *DeviceHandler
165 resourceMgr *rsrcMgr.OpenOltResourceMgr
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700166 onuIds map[onuIDKey]onuInfo //OnuId -> OnuInfo
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400167 onuSerialNumbers map[string]onuInfo //onu serial_number (string) -> OnuInfo
168 onuGemPortIds map[gemPortKey]onuInfo //GemPortId -> OnuInfo
169 packetInGemPort map[packetInInfoKey]uint32 //packet in gem port
170 storedDeviceFlows []ofp.OfpFlowStats /* Required during deletion to obtain device flows from logical flows */
manikkaraj kbf256be2019-03-25 00:13:48 +0530171}
172
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700173//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
manikkaraj kbf256be2019-03-25 00:13:48 +0530174func NewFlowManager(dh *DeviceHandler, rsrcMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
175 log.Info("Initializing flow manager")
176 var flowMgr OpenOltFlowMgr
177 flowMgr.deviceHandler = dh
178 flowMgr.resourceMgr = rsrcMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400179 flowMgr.techprofile = make([]*tp.TechProfileMgr, MaxPonPorts)
manikkaraj kbf256be2019-03-25 00:13:48 +0530180 if err := flowMgr.populateTechProfilePerPonPort(); err != nil {
181 log.Error("Error while populating tech profile mgr\n")
182 return nil
183 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700184 flowMgr.onuIds = make(map[onuIDKey]onuInfo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400185 flowMgr.onuSerialNumbers = make(map[string]onuInfo)
186 flowMgr.onuGemPortIds = make(map[gemPortKey]onuInfo)
187 flowMgr.packetInGemPort = make(map[packetInInfoKey]uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530188 log.Info("Initialization of flow manager success!!")
189 return &flowMgr
190}
191
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700192func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400193 if direction == UPSTREAM {
194 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700195 return 0x1<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400196 } else if direction == DOWNSTREAM {
197 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700198 return uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400199 } else {
200 log.Debug("Unrecognized direction")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700201 return 0, fmt.Errorf("unrecognized direction %s", direction)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400202 }
203}
204
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700205func (f *OpenOltFlowMgr) registerFlow(flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400206 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700207 log.Fields{"device": f.deviceHandler.deviceID})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400208
209 var storedFlow ofp.OfpFlowStats
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700210 storedFlow.Id, _ = f.generateStoredFlowID(deviceFlow.FlowId, deviceFlow.FlowType)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400211 log.Debug(fmt.Sprintf("Generated stored device flow. id = %d, flowId = %d, direction = %s", storedFlow.Id,
212 deviceFlow.FlowId, deviceFlow.FlowType))
213 storedFlow.Cookie = flowFromCore.Id
214 f.storedDeviceFlows = append(f.storedDeviceFlows, storedFlow)
215 log.Debugw("updated Stored flow info", log.Fields{"storedDeviceFlows": f.storedDeviceFlows})
216}
217
Manikkaraj kb1d51442019-07-23 10:41:02 -0400218func (f *OpenOltFlowMgr) divideAndAddFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats, TpId uint32, UsMeterId uint32, DsMeterId uint32, flowMetadata *voltha.FlowMetadata) {
219 var allocId []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530220 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400221 var gemPort uint32
222 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530223
Manikkaraj kb1d51442019-07-23 10:41:02 -0400224 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
225 "classifier": classifierInfo, "action": actionInfo, "UsMeterId": UsMeterId, "DsMeterId": DsMeterId, "TpId": TpId})
Matt Jeanneret77199612019-07-26 18:08:35 -0400226 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
227 // is because the flow is an NNI flow and there would be no onu resources associated with it
228 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400229 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400230 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530231 return
232 }
233
Manikkaraj kb1d51442019-07-23 10:41:02 -0400234 uni := getUniPortPath(intfID, onuID, uniID)
235 log.Debugw("Uni port name", log.Fields{"uni": uni})
236 allocId, gemPorts, TpInst = f.createTcontGemports(intfID, onuID, uniID, uni, portNo, TpId, UsMeterId, DsMeterId, flowMetadata)
237 if allocId == nil || gemPorts == nil || TpInst == nil {
238 log.Error("alloc-id-gem-ports-tp-unavailable")
239 return
240 }
241
242 /* Flows can be added specific to gemport if p-bits are received.
243 * If no pbit mentioned then adding flows for all gemports
manikkaraj kbf256be2019-03-25 00:13:48 +0530244 */
Manikkaraj kb1d51442019-07-23 10:41:02 -0400245
246 args := make(map[string]uint32)
247 args["intfId"] = intfID
248 args["onuId"] = onuID
249 args["uniId"] = uniID
250 args["portNo"] = portNo
251 args["allocId"] = allocId[0]
252
253 if ipProto, ok := classifierInfo[IPProto]; ok {
254 if ipProto.(uint32) == IPProtoDhcp {
255 log.Info("Adding DHCP flow")
256 if pcp, ok := classifierInfo[VlanPcp]; ok {
257 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
258 tp_pb.Direction_UPSTREAM,
259 pcp.(uint32))
260 //Adding DHCP upstream flow
261 f.addDHCPTrapFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
manikkaraj kbf256be2019-03-25 00:13:48 +0530262 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400263 //Adding DHCP upstream flow to all gemports
264 installFlowOnAllGemports(f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
manikkaraj kbf256be2019-03-25 00:13:48 +0530265 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400266
267 } else if ipProto == IgmpProto {
268 log.Info("igmp flow add ignored, not implemented yet")
Chaitrashree G S230040a2019-08-20 20:50:47 -0400269 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530270 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400271 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
Chaitrashree G S230040a2019-08-20 20:50:47 -0400272 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530273 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400274 } else if ethType, ok := classifierInfo[EthType]; ok {
275 if ethType.(uint32) == EapEthType {
276 log.Info("Adding EAPOL flow")
277 var vlanId uint32
278 if val, ok := classifierInfo[VlanVid]; ok {
279 vlanId = (val.(uint32)) & VlanvIDMask
280 } else {
281 vlanId = DefaultMgmtVlan
282 }
283 if pcp, ok := classifierInfo[VlanPcp]; ok {
284 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
285 tp_pb.Direction_UPSTREAM,
286 pcp.(uint32))
287
288 f.addEAPOLFlow(intfID, onuID, uniID, portNo, flow, allocId[0], gemPort, vlanId)
289 } else {
290 installFlowOnAllGemports(nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanId)
291 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400292 }
293 if ethType == LldpEthType {
294 log.Info("Adding LLDP flow")
295 addLLDPFlow(flow, portNo)
Chaitrashree G S230040a2019-08-20 20:50:47 -0400296 return
Manikkaraj kb1d51442019-07-23 10:41:02 -0400297 }
298 } else if _, ok := actionInfo[PushVlan]; ok {
299 log.Info("Adding upstream data rule")
300 if pcp, ok := classifierInfo[VlanPcp]; ok {
301 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
302 tp_pb.Direction_UPSTREAM,
303 pcp.(uint32))
304 //Adding HSIA upstream flow
305 f.addUpstreamDataFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
306 } else {
307 //Adding HSIA upstream flow to all gemports
308 installFlowOnAllGemports(f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
309 }
310 } else if _, ok := actionInfo[PopVlan]; ok {
311 log.Info("Adding Downstream data rule")
312 if pcp, ok := classifierInfo[VlanPcp]; ok {
313 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
314 tp_pb.Direction_UPSTREAM,
315 pcp.(uint32))
316 //Adding HSIA downstream flow
317 f.addDownstreamDataFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
318 } else {
319 //Adding HSIA downstream flow to all gemports
320 installFlowOnAllGemports(f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
321 }
322 } else {
323 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
Chaitrashree G S230040a2019-08-20 20:50:47 -0400324 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530325 }
Chaitrashree G S230040a2019-08-20 20:50:47 -0400326 // Send Techprofile download event to child device in go routine as it takes time
327 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530328}
329
Manikkaraj kb1d51442019-07-23 10:41:02 -0400330func (f *OpenOltFlowMgr) CreateSchedulerQueues(Dir tp_pb.Direction, IntfId uint32, OnuId uint32, UniId uint32, UniPort uint32, TpInst *tp.TechProfile, MeterId uint32, flowMetadata *voltha.FlowMetadata) error {
331
332 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": Dir, "IntfId": IntfId, "OnuId": OnuId,
333 "UniId": UniId, "MeterId": MeterId, "TpInst": *TpInst, "flowMetadata": flowMetadata})
334
335 if MeterId == 0 { // This should never happen
336 log.Error("Invalid meter id")
337 return errors.New("Invalid meter id")
338 }
339
340 /* Lets make a simple assumption that if the meter-id is present on the KV store,
341 * then the scheduler and queues configuration is applied on the OLT device
342 * in the given direction.
343 */
344 var Direction string
345 var SchedCfg *tp_pb.SchedulerConfig
346 if Dir == tp_pb.Direction_UPSTREAM {
347 Direction = "upstream"
348 } else if Dir == tp_pb.Direction_DOWNSTREAM {
349 Direction = "downstream"
350 }
351 KvStoreMeter, err := f.resourceMgr.GetMeterIdForOnu(Direction, IntfId, OnuId, UniId)
352 if err != nil {
353 log.Error("Failed to get meter for intf %d, onuid %d, uniid %d", IntfId, OnuId, UniId)
354 return err
355 }
356 if KvStoreMeter != nil {
357 if KvStoreMeter.MeterId == MeterId {
358 log.Debug("Scheduler already created for upstream")
359 return nil
360 } else {
361 log.Errorw("Dynamic meter update not supported", log.Fields{"KvStoreMeterId": KvStoreMeter.MeterId, "MeterId-in-flow": MeterId})
362 return errors.New("Invalid-meter-id-in-flow")
363 }
364 }
365 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterId": MeterId, "Direction": Direction})
366 if Dir == tp_pb.Direction_UPSTREAM {
367 SchedCfg = f.techprofile[IntfId].GetUsScheduler(TpInst)
368 } else if Dir == tp_pb.Direction_DOWNSTREAM {
369 SchedCfg = f.techprofile[IntfId].GetDsScheduler(TpInst)
370 }
371 var meterConfig *ofp.OfpMeterConfig
372 if flowMetadata != nil {
373 for _, meter := range flowMetadata.Meters {
374 if MeterId == meter.MeterId {
375 meterConfig = meter
376 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
377 break
378 }
379 }
380 } else {
381 log.Error("Flow-metadata-is-not-present-in-flow")
382 }
383 if meterConfig == nil {
384 log.Errorw("Could-not-get-meterbands-from-flowMetadata", log.Fields{"flowMetadata": flowMetadata, "MeterId": MeterId})
385 return errors.New("Failed-to-get-meter-from-flowMetadata")
386 } else if len(meterConfig.Bands) < MaxMeterBand {
387 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterId": MeterId})
388 return errors.New("Invalid-number-of-bands-in-meter")
389 }
390 cir := meterConfig.Bands[0].Rate
391 cbs := meterConfig.Bands[0].BurstSize
392 eir := meterConfig.Bands[1].Rate
393 ebs := meterConfig.Bands[1].BurstSize
394 pir := cir + eir
395 pbs := cbs + ebs
396 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
397
398 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[IntfId].GetTrafficScheduler(TpInst, SchedCfg, TrafficShaping)}
399
400 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": Direction, "TrafficScheds": TrafficSched})
401 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(context.Background(), &tp_pb.TrafficSchedulers{
402 IntfId: IntfId, OnuId: OnuId,
403 UniId: UniId, PortNo: UniPort,
404 TrafficScheds: TrafficSched}); err != nil {
405 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
406 return err
407 }
408 // On receiving the CreateTrafficQueues request, the driver should create corresponding
409 // downstream queues.
410 trafficQueues := f.techprofile[IntfId].GetTrafficQueues(TpInst, Dir)
411 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": Direction, "TrafficQueues": trafficQueues})
412 if _, err := f.deviceHandler.Client.CreateTrafficQueues(context.Background(),
413 &tp_pb.TrafficQueues{IntfId: IntfId, OnuId: OnuId,
414 UniId: UniId, PortNo: UniPort,
415 TrafficQueues: trafficQueues}); err != nil {
416 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
417 return err
418 }
419
420 /* After we succesfully applied the scheduler configuration on the OLT device,
421 * store the meter id on the KV store, for further reference.
422 */
423 if err := f.resourceMgr.UpdateMeterIdForOnu(Direction, IntfId, OnuId, UniId, meterConfig); err != nil {
424 log.Error("Failed to update meter id for onu %d, meterid %d", OnuId, MeterId)
425 return err
426 }
427 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
428 "Meter": meterConfig})
429 return nil
430}
431
432func (f *OpenOltFlowMgr) RemoveSchedulerQueues(Dir tp_pb.Direction, IntfId uint32, OnuId uint32, UniId uint32, UniPort uint32, TpInst *tp.TechProfile) error {
433
434 var Direction string
435 var SchedCfg *tp_pb.SchedulerConfig
436 var err error
437 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": Dir, "IntfId": IntfId, "OnuId": OnuId, "UniId": UniId, "UniPort": UniPort})
438 if Dir == tp_pb.Direction_UPSTREAM {
439 SchedCfg = f.techprofile[IntfId].GetUsScheduler(TpInst)
440 Direction = "upstream"
441 } else if Dir == tp_pb.Direction_DOWNSTREAM {
442 SchedCfg = f.techprofile[IntfId].GetDsScheduler(TpInst)
443 Direction = "downstream"
444 }
445
446 KVStoreMeter, err := f.resourceMgr.GetMeterIdForOnu(Direction, IntfId, OnuId, UniId)
447 if err != nil {
448 log.Errorf("Failed to get Meter for Onu %d", OnuId)
449 return err
450 }
451 if KVStoreMeter == nil {
452 log.Debugw("No-meter-has-been-installed-yet", log.Fields{"direction": Direction, "IntfId": IntfId, "OnuId": OnuId, "UniId": UniId})
453 return nil
454 }
455 cir := KVStoreMeter.Bands[0].Rate
456 cbs := KVStoreMeter.Bands[0].BurstSize
457 eir := KVStoreMeter.Bands[1].Rate
458 ebs := KVStoreMeter.Bands[1].BurstSize
459 pir := cir + eir
460 pbs := cbs + ebs
461
462 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
463
464 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[IntfId].GetTrafficScheduler(TpInst, SchedCfg, TrafficShaping)}
465 TrafficQueues := f.techprofile[IntfId].GetTrafficQueues(TpInst, Dir)
466
467 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(context.Background(),
468 &tp_pb.TrafficQueues{IntfId: IntfId, OnuId: OnuId,
469 UniId: UniId, PortNo: UniPort,
470 TrafficQueues: TrafficQueues}); err != nil {
471 log.Error("Failed to remove traffic queues")
472 return err
473 } else {
474 log.Debug("Removed traffic queues successfully")
475 }
476 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(context.Background(), &tp_pb.TrafficSchedulers{
477 IntfId: IntfId, OnuId: OnuId,
478 UniId: UniId, PortNo: UniPort,
479 TrafficScheds: TrafficSched}); err != nil {
480 log.Error("failed to remove traffic schedulers")
481 return err
482 } else {
483 log.Debug("Removed traffic schedulers successfully")
484 }
485
486 /* After we succesfully remove the scheduler configuration on the OLT device,
487 * delete the meter id on the KV store.
488 */
489 err = f.resourceMgr.RemoveMeterIdForOnu(Direction, IntfId, OnuId, UniId)
490 if err != nil {
491 log.Errorf("Failed to remove meter for onu %d, meter id %d", OnuId, KVStoreMeter.MeterId)
492 }
493 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
494 return err
495}
496
manikkaraj kbf256be2019-03-25 00:13:48 +0530497// This function allocates tconts and GEM ports for an ONU, currently one TCONT is supported per ONU
Manikkaraj kb1d51442019-07-23 10:41:02 -0400498func (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) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530499 var allocID []uint32
500 var gemPortIDs []uint32
501 //If we already have allocated earlier for this onu, render them
Manikkaraj kb1d51442019-07-23 10:41:02 -0400502 if tcontId := f.resourceMgr.GetCurrentAllocIDForOnu(intfID, onuID, uniID); tcontId != 0 {
503 allocID = append(allocID, tcontId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530504 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700505 gemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400506
507 tpPath := f.getTPpath(intfID, uni, TpID)
508 // Check tech profile instance already exists for derived port name
509 tech_profile_instance, err := f.techprofile[intfID].GetTPInstanceFromKVStore(TpID, tpPath)
510 if err != nil { // This should not happen, something wrong in KV backend transaction
511 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": TpID, "path": tpPath})
512 return nil, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530513 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400514
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700515 log.Debug("Creating New TConts and Gem ports", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530516
Manikkaraj kb1d51442019-07-23 10:41:02 -0400517 if tech_profile_instance == nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530518 log.Info("Creating tech profile instance", log.Fields{"path": tpPath})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400519 tech_profile_instance = f.techprofile[intfID].CreateTechProfInstance(TpID, uni, intfID)
520 if tech_profile_instance == nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530521 log.Error("Tech-profile-instance-creation-failed")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400522 return nil, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530523 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400524 f.resourceMgr.UpdateTechProfileIdForOnu(intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530525 } else {
526 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
527 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400528 if UsMeterID != 0 {
529 if err := f.CreateSchedulerQueues(tp_pb.Direction_UPSTREAM, intfID, onuID, uniID, uniPort, tech_profile_instance, UsMeterID, flowMetadata); err != nil {
530 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
531 return nil, nil, nil
532 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530533 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400534 if DsMeterID != 0 {
535 if err := f.CreateSchedulerQueues(tp_pb.Direction_DOWNSTREAM, intfID, onuID, uniID, uniPort, tech_profile_instance, DsMeterID, flowMetadata); err != nil {
536 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
537 return nil, nil, nil
538 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530539 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400540 if len(allocID) == 0 { // Created TCONT first time
541 allocID = append(allocID, tech_profile_instance.UsScheduler.AllocID)
542 }
543 if len(gemPortIDs) == 0 { // Create GEM ports first time
544 for _, gem := range tech_profile_instance.UpstreamGemPortAttributeList {
545 gemPortIDs = append(gemPortIDs, gem.GemportID)
546 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530547 }
548 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocID": allocID, "gemports": gemPortIDs})
549 // Send Tconts and GEM ports to KV store
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700550 f.storeTcontsGEMPortsIntoKVStore(intfID, onuID, uniID, allocID, gemPortIDs)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400551 return allocID, gemPortIDs, tech_profile_instance
manikkaraj kbf256be2019-03-25 00:13:48 +0530552}
553
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700554func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530555
556 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700557 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530558 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700559 if err := f.resourceMgr.UpdateAllocIdsForOnu(intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530560 log.Error("Errow while uploading allocID to KV store")
561 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700562 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530563 log.Error("Errow while uploading GEMports to KV store")
564 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700565 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530566 log.Error("Errow while uploading gemtopon map to KV store")
567 }
568 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400569 for _, gemPort := range gemPortIDs {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700570 f.addGemPortToOnuInfoMap(intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400571 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530572}
573
574func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400575 var tpCount int = 0
manikkaraj kbf256be2019-03-25 00:13:48 +0530576 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400577 for _, intfId := range techRange.IntfIds {
578 f.techprofile[intfId] = f.resourceMgr.ResourceMgrs[uint32(intfId)].TechProfileMgr
579 tpCount++
580 log.Debugw("Init tech profile done", log.Fields{"intfId": intfId})
manikkaraj kbf256be2019-03-25 00:13:48 +0530581 }
582 }
583 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400584 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530585 log.Errorw("Error while populating techprofile",
Manikkaraj kb1d51442019-07-23 10:41:02 -0400586 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
587 return errors.New("Error while populating techprofile mgrs")
manikkaraj kbf256be2019-03-25 00:13:48 +0530588 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400589 log.Infow("Populated techprofile for ponports successfully",
590 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530591 return nil
592}
593
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700594func (f *OpenOltFlowMgr) addUpstreamDataFlow(intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530595 portNo uint32, uplinkClassifier map[string]interface{},
596 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700597 allocID uint32, gemportID uint32) {
598 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530599 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700600 f.addHSIAFlow(intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
601 UPSTREAM, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530602 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530603}
604
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700605func (f *OpenOltFlowMgr) addDownstreamDataFlow(intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530606 portNo uint32, downlinkClassifier map[string]interface{},
607 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700608 allocID uint32, gemportID uint32) {
609 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530610 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
611 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400612 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
613 if vlan, exists := downlinkClassifier[VlanVid]; exists {
614 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
615 if metadata, exists := downlinkClassifier[METADATA]; exists { // inport is filled in metadata by core
616 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
617 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
618 return
619 }
620 }
621 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530622 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400623
Manikkaraj k884c1242019-04-11 16:26:42 +0530624 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700625 downlinkAction[PopVlan] = true
626 downlinkAction[VlanVid] = downlinkClassifier[VlanVid]
627 f.addHSIAFlow(intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
628 DOWNSTREAM, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530629}
630
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700631func (f *OpenOltFlowMgr) addHSIAFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Manikkaraj k884c1242019-04-11 16:26:42 +0530632 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700633 allocID uint32, gemPortID uint32) {
Manikkaraj k884c1242019-04-11 16:26:42 +0530634 /* One of the OLT platform (Broadcom BAL) requires that symmetric
635 flows require the same flow_id to be used across UL and DL.
636 Since HSIA flow is the only symmetric flow currently, we need to
637 re-use the flow_id across both direction. The 'flow_category'
638 takes priority over flow_cookie to find any available HSIA_FLOW
639 id for the ONU.
640 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700641 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
642 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530643 "logicalFlow": *logicalFlow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400644 var vlan_pit uint32 = 0
645 if _, ok := classifier[VlanPcp]; ok {
646 vlan_pit = classifier[VlanPcp].(uint32)
647 log.Debugw("Found pbit in the flow", log.Fields{"vlan_pit": vlan_pit})
648 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700649 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400650 flowId, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, HsiaFlow, vlan_pit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530651 if err != nil {
652 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
653 return
654 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700655 var classifierProto *openoltpb2.Classifier
656 var actionProto *openoltpb2.Action
Manikkaraj k884c1242019-04-11 16:26:42 +0530657 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
658 log.Error("Error in making classifier protobuf for hsia flow")
659 return
660 }
661 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
662 if actionProto = makeOpenOltActionField(action); actionProto == nil {
663 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
664 return
665 }
666 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700667 networkIntfID := f.deviceHandler.nniIntfID
668 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
669 OnuId: int32(onuID),
670 UniId: int32(uniID),
Manikkaraj kb1d51442019-07-23 10:41:02 -0400671 FlowId: flowId,
Manikkaraj k884c1242019-04-11 16:26:42 +0530672 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700673 AllocId: int32(allocID),
674 NetworkIntfId: int32(networkIntfID),
675 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530676 Classifier: classifierProto,
677 Action: actionProto,
678 Priority: int32(logicalFlow.Priority),
679 Cookie: logicalFlow.Cookie,
680 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400681 if ok := f.addFlowToDevice(logicalFlow, &flow); ok {
Manikkaraj k884c1242019-04-11 16:26:42 +0530682 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400683 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, HsiaFlow, flowId)
Manikkaraj k884c1242019-04-11 16:26:42 +0530684 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
685 flow.OnuId,
686 flow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400687 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530688 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
689 return
690 }
691 }
692}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700693func (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 +0530694
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700695 var dhcpFlow openoltpb2.Flow
696 var actionProto *openoltpb2.Action
697 var classifierProto *openoltpb2.Classifier
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530698
699 // Clear the action map
700 for k := range action {
701 delete(action, k)
702 }
703
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700704 action[TrapToHost] = true
705 classifier[UDPSrc] = uint32(68)
706 classifier[UDPDst] = uint32(67)
707 classifier[PacketTagType] = SingleTag
708 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530709
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700710 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530711
Manikkaraj kb1d51442019-07-23 10:41:02 -0400712 flowID, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, "", 0 /*classifier[VLAN_PCP].(uint32)*/)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530713
714 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700715 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530716 return
717 }
718
719 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
720
721 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
722 log.Error("Error in making classifier protobuf for ul flow")
723 return
724 }
725 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
726 if actionProto = makeOpenOltActionField(action); actionProto == nil {
727 log.Error("Error in making action protobuf for ul flow")
728 return
729 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700730 networkIntfID := f.deviceHandler.nniIntfID
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530731
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700732 dhcpFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
733 OnuId: int32(onuID),
734 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530735 FlowId: flowID,
736 FlowType: UPSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700737 AllocId: int32(allocID),
738 NetworkIntfId: int32(networkIntfID),
739 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530740 Classifier: classifierProto,
741 Action: actionProto,
742 Priority: int32(logicalFlow.Priority),
743 Cookie: logicalFlow.Cookie,
744 PortNo: portNo}
745
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400746 if ok := f.addFlowToDevice(logicalFlow, &dhcpFlow); ok {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530747 log.Debug("DHCP UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400748 flowsToKVStore := f.getUpdatedFlowInfo(&dhcpFlow, flowStoreCookie, "DHCP", flowID)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530749 if err := f.updateFlowInfoToKVStore(dhcpFlow.AccessIntfId,
750 dhcpFlow.OnuId,
751 dhcpFlow.UniId,
752 dhcpFlow.FlowId, flowsToKVStore); err != nil {
753 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
754 return
755 }
756 }
757
manikkaraj kbf256be2019-03-25 00:13:48 +0530758 return
759}
760
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700761// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
762func (f *OpenOltFlowMgr) addEAPOLFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, vlanID uint32) {
763 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 +0530764
765 uplinkClassifier := make(map[string]interface{})
766 uplinkAction := make(map[string]interface{})
767 downlinkClassifier := make(map[string]interface{})
768 downlinkAction := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700769 var upstreamFlow openoltpb2.Flow
770 var downstreamFlow openoltpb2.Flow
manikkaraj kbf256be2019-03-25 00:13:48 +0530771
772 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700773 uplinkClassifier[EthType] = uint32(EapEthType)
774 uplinkClassifier[PacketTagType] = SingleTag
775 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530776 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700777 uplinkAction[TrapToHost] = true
778 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530779 //Add Uplink EAPOL Flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400780 uplinkFlowID, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530781 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700782 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manikkaraj k884c1242019-04-11 16:26:42 +0530783 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530784 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700785 var classifierProto *openoltpb2.Classifier
786 var actionProto *openoltpb2.Action
787 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530788
789 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
790 log.Error("Error in making classifier protobuf for ul flow")
791 return
792 }
793 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
794 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
795 log.Error("Error in making action protobuf for ul flow")
796 return
797 }
798 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700799 networkIntfID := f.deviceHandler.nniIntfID
800 upstreamFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
801 OnuId: int32(onuID),
802 UniId: int32(uniID),
803 FlowId: uplinkFlowID,
manikkaraj kbf256be2019-03-25 00:13:48 +0530804 FlowType: UPSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700805 AllocId: int32(allocID),
806 NetworkIntfId: int32(networkIntfID),
807 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +0530808 Classifier: classifierProto,
809 Action: actionProto,
810 Priority: int32(logicalFlow.Priority),
811 Cookie: logicalFlow.Cookie,
812 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400813 if ok := f.addFlowToDevice(logicalFlow, &upstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530814 log.Debug("EAPOL UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400815 flowCategory := "EAPOL"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700816 flowsToKVStore := f.getUpdatedFlowInfo(&upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530817 if err := f.updateFlowInfoToKVStore(upstreamFlow.AccessIntfId,
818 upstreamFlow.OnuId,
819 upstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400820 upstreamFlow.FlowId,
821 /* lowCategory, */
822 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530823 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
824 return
825 }
826 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400827 // Dummy Downstream flow due to BAL 2.6 limitation
828 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530829 /* Add Downstream EAPOL Flow, Only for first EAP flow (BAL
830 # requirement)
831 # On one of the platforms (Broadcom BAL), when same DL classifier
832 # vlan was used across multiple ONUs, eapol flow re-adds after
833 # flow delete (cases of onu reboot/disable) fails.
834 # In order to generate unique vlan, a combination of intf_id
835 # onu_id and uniId is used.
836 # uniId defaults to 0, so add 1 to it.
837 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700838 log.Debugw("Creating DL EAPOL flow with default vlan", log.Fields{"vlan": vlanID})
839 specialVlanDlFlow := 4090 - intfID*onuID*(uniID+1)
manikkaraj kbf256be2019-03-25 00:13:48 +0530840 // Assert that we do not generate invalid vlans under no condition
841 if specialVlanDlFlow <= 2 {
842 log.Fatalw("invalid-vlan-generated", log.Fields{"vlan": specialVlanDlFlow})
843 return
844 }
845 log.Debugw("specialVlanEAPOLDlFlow:", log.Fields{"dl_vlan": specialVlanDlFlow})
846 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700847 downlinkClassifier[PacketTagType] = SingleTag
Manikkaraj kb1d51442019-07-23 10:41:02 -0400848 downlinkClassifier[EthType] = uint32(EapEthType)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700849 downlinkClassifier[VlanVid] = uint32(specialVlanDlFlow)
manikkaraj kbf256be2019-03-25 00:13:48 +0530850 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700851 downlinkAction[PushVlan] = true
852 downlinkAction[VlanVid] = vlanID
853 flowStoreCookie := getFlowStoreCookie(downlinkClassifier, gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400854 downlinkFlowId, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530855 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530856 log.Errorw("flowId unavailable for DL EAPOL",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700857 log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
manikkaraj kbf256be2019-03-25 00:13:48 +0530858 return
859 }
860 log.Debugw("Creating DL EAPOL flow",
Manikkaraj kb1d51442019-07-23 10:41:02 -0400861 log.Fields{"dl_classifier": downlinkClassifier, "dl_action": downlinkAction, "downlinkFlowId": downlinkFlowId})
manikkaraj kbf256be2019-03-25 00:13:48 +0530862 if classifierProto = makeOpenOltClassifierField(downlinkClassifier); classifierProto == nil {
863 log.Error("Error in making classifier protobuf for downlink flow")
864 return
865 }
866 if actionProto = makeOpenOltActionField(downlinkAction); actionProto == nil {
867 log.Error("Error in making action protobuf for dl flow")
868 return
869 }
870 // Downstream flow in grpc protobuf
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700871 downstreamFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
872 OnuId: int32(onuID),
873 UniId: int32(uniID),
Manikkaraj kb1d51442019-07-23 10:41:02 -0400874 FlowId: downlinkFlowId,
manikkaraj kbf256be2019-03-25 00:13:48 +0530875 FlowType: DOWNSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700876 AllocId: int32(allocID),
877 NetworkIntfId: int32(networkIntfID),
878 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +0530879 Classifier: classifierProto,
880 Action: actionProto,
881 Priority: int32(logicalFlow.Priority),
882 Cookie: logicalFlow.Cookie,
883 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400884 if ok := f.addFlowToDevice(logicalFlow, &downstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530885 log.Debug("EAPOL DL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400886 flowCategory := ""
Manikkaraj kb1d51442019-07-23 10:41:02 -0400887 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamFlow, flowStoreCookie, flowCategory, downlinkFlowId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530888 if err := f.updateFlowInfoToKVStore(downstreamFlow.AccessIntfId,
889 downstreamFlow.OnuId,
890 downstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400891 downstreamFlow.FlowId,
892 /* flowCategory, */
893 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530894 log.Errorw("Error uploading EAPOL DL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
895 return
896 }
897 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530898 }
899 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
900}
901
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700902func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openoltpb2.Classifier {
903 var classifier openoltpb2.Classifier
904 if etherType, ok := classifierInfo[EthType]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530905 classifier.EthType = etherType.(uint32)
906 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700907 if ipProto, ok := classifierInfo[IPProto]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530908 classifier.IpProto = ipProto.(uint32)
909 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700910 if vlanID, ok := classifierInfo[VlanVid]; ok {
Harsh Awasthie9644e02019-08-26 02:39:00 -0400911 vid := (vlanID.(uint32)) & VlanvIDMask
912 if vid != RESERVED_VLAN {
913 classifier.OVid = vid
914 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530915 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400916 if metadata, ok := classifierInfo[METADATA]; ok {
Harsh Awasthie9644e02019-08-26 02:39:00 -0400917 vid := uint32(metadata.(uint64))
918 if vid != RESERVED_VLAN {
919 classifier.IVid = vid
920 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530921 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700922 if vlanPcp, ok := classifierInfo[VlanPcp]; ok {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400923 if vlanPcp == 0 {
924 classifier.OPbits = VlanPCPMask
925 } else {
926 classifier.OPbits = (vlanPcp.(uint32)) & VlanPCPMask
927 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530928 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700929 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530930 classifier.SrcPort = udpSrc.(uint32)
931 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700932 if udpDst, ok := classifierInfo[UDPDst]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530933 classifier.DstPort = udpDst.(uint32)
934 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700935 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530936 classifier.DstIp = ipv4Dst.(uint32)
937 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700938 if ipv4Src, ok := classifierInfo[Ipv4Src]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530939 classifier.SrcIp = ipv4Src.(uint32)
940 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700941 if pktTagType, ok := classifierInfo[PacketTagType]; ok {
942 if pktTagType.(string) == SingleTag {
943 classifier.PktTagType = SingleTag
944 } else if pktTagType.(string) == DoubleTag {
945 classifier.PktTagType = DoubleTag
manikkaraj kbf256be2019-03-25 00:13:48 +0530946 } else if pktTagType.(string) == UNTAGGED {
947 classifier.PktTagType = UNTAGGED
948 } else {
949 log.Error("Invalid tag type in classifier") // should not hit
950 return nil
951 }
952 }
953 return &classifier
954}
955
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700956func makeOpenOltActionField(actionInfo map[string]interface{}) *openoltpb2.Action {
957 var actionCmd openoltpb2.ActionCmd
958 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +0530959 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700960 if _, ok := actionInfo[PopVlan]; ok {
961 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530962 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700963 } else if _, ok := actionInfo[PushVlan]; ok {
964 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530965 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700966 } else if _, ok := actionInfo[TrapToHost]; ok {
967 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +0530968 } else {
969 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
970 return nil
971 }
972 return &action
973}
974
Manikkaraj kb1d51442019-07-23 10:41:02 -0400975func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
976 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +0530977}
978
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700979func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530980 if len(classifier) == 0 { // should never happen
981 log.Error("Invalid classfier object")
982 return 0
983 }
984 var jsonData []byte
985 var flowString string
986 var err error
987 // TODO: Do we need to marshall ??
988 if jsonData, err = json.Marshal(classifier); err != nil {
989 log.Error("Failed to encode classifier")
990 return 0
991 }
992 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700993 if gemPortID != 0 {
994 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +0530995 }
996 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700997 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +0530998 hash := big.NewInt(0)
999 hash.SetBytes(h.Sum(nil))
1000 return hash.Uint64()
1001}
1002
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001003func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openoltpb2.Flow, flowStoreCookie uint64, flowCategory string, deviceFlowID uint32) *[]rsrcMgr.FlowInfo {
1004 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1005 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001006 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1007 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1008 */
1009 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001010 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001011 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001012 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001013 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001014 // Get existing flows matching flowid for given subscriber from KV store
1015 existingFlows := f.resourceMgr.GetFlowIDInfo(intfID, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001016 if existingFlows != nil {
1017 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001018 //for _, f := range *existingFlows {
1019 // flows = append(flows, f)
1020 //}
1021 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001022 }
1023 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 +05301024 return &flows
1025}
1026
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001027//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1028// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1029// var intfId uint32
1030// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1031// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1032// */
1033// if flow.AccessIntfId != -1 {
1034// intfId = uint32(flow.AccessIntfId)
1035// } else {
1036// intfId = uint32(flow.NetworkIntfId)
1037// }
1038// // Get existing flows matching flowid for given subscriber from KV store
1039// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1040// if existingFlows != nil {
1041// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1042// for _, f := range *existingFlows {
1043// flows = append(flows, f)
1044// }
1045// }
1046// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1047// return &flows
1048//}
1049
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001050func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(intfID int32, onuID int32, uniID int32, flowID uint32, flows *[]rsrcMgr.FlowInfo) error {
manikkaraj k17652a72019-05-06 09:06:36 -04001051 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001052 if err := f.resourceMgr.UpdateFlowIDInfo(intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001053 log.Debug("Error while Storing flow into KV store")
1054 return err
1055 }
1056 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301057 return nil
1058}
1059
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001060func (f *OpenOltFlowMgr) addFlowToDevice(logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) bool {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001061
1062 var intfID uint32
1063 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1064 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1065 */
1066 if deviceFlow.AccessIntfId != -1 {
1067 intfID = uint32(deviceFlow.AccessIntfId)
1068 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001069 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001070 intfID = uint32(deviceFlow.NetworkIntfId)
1071 }
1072
manikkaraj kbf256be2019-03-25 00:13:48 +05301073 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1074 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001075
1076 st, _ := status.FromError(err)
1077 if st.Code() == codes.AlreadyExists {
1078 log.Debug("Flow already exixts", log.Fields{"err": err, "deviceFlow": deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +05301079 return false
1080 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001081
1082 if err != nil {
1083 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
1084 f.resourceMgr.FreeFlowID(intfID, uint32(deviceFlow.OnuId), uint32(deviceFlow.UniId), deviceFlow.FlowId)
1085 return false
1086 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001087 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001088 f.registerFlow(logicalFlow, deviceFlow)
1089 return true
1090}
1091
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001092func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) bool {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001093 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1094 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1095 if err != nil {
1096 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
1097 return false
1098 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001099 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +05301100 return true
1101}
1102
1103/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1104 //update core flows_proxy : flows_proxy.update('/', flows)
1105}
1106
1107func generateStoredId(flowId uint32, direction string)uint32{
1108
1109 if direction == UPSTREAM{
1110 log.Debug("Upstream flow shifting flowid")
1111 return ((0x1 << 15) | flowId)
1112 }else if direction == DOWNSTREAM{
1113 log.Debug("Downstream flow not shifting flowid")
1114 return flowId
1115 }else{
1116 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1117 return flowId
1118 }
1119}
1120
1121*/
1122
1123func addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001124 log.Info("unimplemented flow : %v, portNo : %v ", flow, portNo)
manikkaraj kbf256be2019-03-25 00:13:48 +05301125}
1126
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001127func getUniPortPath(intfID uint32, onuID uint32, uniID uint32) string {
1128 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1129}
1130
1131//getOnuChildDevice to fetch onu
1132func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1133 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1134 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
1135 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301136 if onuDevice == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001137 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301138 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +05301139 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301140 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1141 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301142}
1143
1144func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001145 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301146 return nil
1147}
1148
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001149func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1150 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301151}
1152
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001153func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001154 if id>>15 == 0x1 {
1155 return id & 0x7fff, UPSTREAM
1156 }
1157 return id, DOWNSTREAM
1158}
1159
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001160func (f *OpenOltFlowMgr) clearFlowFromResourceManager(flow *ofp.OfpFlowStats, flowID uint32, flowDirection string) {
1161 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowID": flowID, "flowDirection": flowDirection, "flow": *flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001162 portNum, ponIntf, onuID, uniID, err := FlowExtractInfo(flow, flowDirection)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001163 if err != nil {
1164 log.Error(err)
1165 return
1166 }
1167 log.Debugw("Extracted access info from flow to be deleted",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001168 log.Fields{"ponIntf": ponIntf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001169
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001170 flowsInfo := f.resourceMgr.GetFlowIDInfo(ponIntf, onuID, uniID, flowID)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001171 if flowsInfo == nil {
1172 log.Debugw("No FlowInfo found found in KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001173 log.Fields{"ponIntf": ponIntf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001174 return
1175 }
1176 var updatedFlows []rsrcMgr.FlowInfo
1177
1178 for _, flow := range *flowsInfo {
1179 updatedFlows = append(updatedFlows, flow)
1180 }
1181
1182 for i, storedFlow := range updatedFlows {
1183 if flowDirection == storedFlow.Flow.FlowType {
1184 //Remove the Flow from FlowInfo
1185 log.Debugw("Removing flow to be deleted", log.Fields{"flow": storedFlow})
1186 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1187 break
1188 }
1189 }
1190
1191 if len(updatedFlows) >= 0 {
1192 // There are still flows referencing the same flow_id.
1193 // So the flow should not be freed yet.
1194 // For ex: Case of HSIA where same flow is shared
1195 // between DS and US.
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001196 f.updateFlowInfoToKVStore(int32(ponIntf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001197 if len(updatedFlows) == 0 {
1198 log.Debugw("Releasing flow Id to resource manager", log.Fields{"ponIntf": ponIntf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
1199 f.resourceMgr.FreeFlowID(ponIntf, onuID, uniID, flowID)
1200 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001201 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001202 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ponIntf, onuID, uniID)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001203 if len(flowIds) == 0 {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001204 log.Debugf("Flow count for subscriber %d is zero", onuID)
1205 kvstoreTpId := f.resourceMgr.GetTechProfileIdForOnu(ponIntf, onuID, uniID)
1206 if kvstoreTpId == 0 {
1207 log.Warnw("Could-not-find-techprofile-tableid-for-uni", log.Fields{"ponIntf": ponIntf, "onuId": onuID, "uniId": uniID})
1208 return
1209 }
1210 uni := getUniPortPath(ponIntf, onuID, uniID)
1211 tpPath := f.getTPpath(ponIntf, uni, kvstoreTpId)
1212 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
1213 techprofileInst, err := f.techprofile[ponIntf].GetTPInstanceFromKVStore(kvstoreTpId, tpPath)
1214 if err != nil { // This should not happen, something wrong in KV backend transaction
1215 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
1216 return
1217 }
1218 if techprofileInst == nil {
1219 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
1220 return
1221 }
1222
1223 f.RemoveSchedulerQueues(tp_pb.Direction_UPSTREAM, ponIntf, onuID, uniID, portNum, techprofileInst)
1224 f.RemoveSchedulerQueues(tp_pb.Direction_DOWNSTREAM, ponIntf, onuID, uniID, portNum, techprofileInst)
1225 } else {
1226 log.Debugf("Flow ids for subscriber", log.Fields{"onu": onuID, "flows": flowIds})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001227 }
1228}
1229
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001230//RemoveFlow removes the flow from the device
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001231func (f *OpenOltFlowMgr) RemoveFlow(flow *ofp.OfpFlowStats) {
1232 log.Debugw("Removing Flow", log.Fields{"flow": flow})
1233 var deviceFlowsToRemove []ofp.OfpFlowStats
1234 var deletedFlowsIdx []int
1235 for _, curFlow := range f.storedDeviceFlows {
1236 if curFlow.Cookie == flow.Id {
1237 log.Debugw("Found found matching flow-cookie", log.Fields{"curFlow": curFlow})
1238 deviceFlowsToRemove = append(deviceFlowsToRemove, curFlow)
1239 }
1240 }
1241 log.Debugw("Flows to be deleted", log.Fields{"deviceFlowsToRemove": deviceFlowsToRemove})
1242 for index, curFlow := range deviceFlowsToRemove {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001243 id, direction := f.decodeStoredID(curFlow.GetId())
1244 removeFlowMessage := openoltpb2.Flow{FlowId: uint32(id), FlowType: direction}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001245 if ok := f.removeFlowFromDevice(&removeFlowMessage); ok {
1246 log.Debug("Flow removed from device successfully")
1247 deletedFlowsIdx = append(deletedFlowsIdx, index)
1248 f.clearFlowFromResourceManager(flow, uint32(id), direction) //TODO: Take care of the limitations
1249 }
1250
1251 }
1252 // Can be done in separate go routine as it takes time ?
1253 for _, flowToRemove := range deletedFlowsIdx {
1254 for index, storedFlow := range f.storedDeviceFlows {
1255 if deviceFlowsToRemove[flowToRemove].Cookie == storedFlow.Cookie {
1256 log.Debugw("Removing flow from local Store", log.Fields{"flow": storedFlow})
1257 f.storedDeviceFlows = append(f.storedDeviceFlows[:index], f.storedDeviceFlows[index+1:]...)
1258 break
1259 }
1260 }
1261 }
1262 log.Debugw("Flows removed from the data store",
1263 log.Fields{"number_of_flows_removed": len(deviceFlowsToRemove), "updated_stored_flows": f.storedDeviceFlows})
1264 return
1265}
1266
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001267// AddFlow add flow to device
Manikkaraj kb1d51442019-07-23 10:41:02 -04001268func (f *OpenOltFlowMgr) AddFlow(flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001269 classifierInfo := make(map[string]interface{})
1270 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001271 var UsMeterID uint32
1272 var DsMeterID uint32
1273
1274 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001275 for _, field := range utils.GetOfbFields(flow) {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001276 if field.Type == utils.ETH_TYPE {
1277 classifierInfo[EthType] = field.GetEthType()
1278 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
1279 } else if field.Type == utils.IP_PROTO {
1280 classifierInfo[IPProto] = field.GetIpProto()
1281 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1282 } else if field.Type == utils.IN_PORT {
1283 classifierInfo[InPort] = field.GetPort()
1284 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
1285 } else if field.Type == utils.VLAN_VID {
1286 classifierInfo[VlanVid] = field.GetVlanVid()
1287 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
1288 } else if field.Type == utils.VLAN_PCP {
1289 classifierInfo[VlanPcp] = field.GetVlanPcp()
1290 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
1291 } else if field.Type == utils.UDP_DST {
1292 classifierInfo[UDPDst] = field.GetUdpDst()
1293 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
1294 } else if field.Type == utils.UDP_SRC {
1295 classifierInfo[UDPSrc] = field.GetUdpSrc()
1296 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
1297 } else if field.Type == utils.IPV4_DST {
1298 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
1299 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
1300 } else if field.Type == utils.IPV4_SRC {
1301 classifierInfo[Ipv4Src] = field.GetIpv4Src()
1302 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
1303 } else if field.Type == utils.METADATA {
1304 classifierInfo[METADATA] = field.GetTableMetadata()
1305 log.Debug("field-type-metadata", log.Fields{"classifierInfo[METADATA]": classifierInfo[METADATA].(uint64)})
1306 } else if field.Type == utils.TUNNEL_ID {
1307 classifierInfo[TunnelID] = field.GetTunnelId()
1308 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
1309 } else {
1310 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
1311 return
1312 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301313 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001314 for _, action := range utils.GetActions(flow) {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001315 if action.Type == utils.OUTPUT {
1316 if out := action.GetOutput(); out != nil {
1317 actionInfo[OUTPUT] = out.GetPort()
1318 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[OUTPUT].(uint32)})
1319 } else {
1320 log.Error("Invalid output port in action")
1321 return
1322 }
1323 } else if action.Type == utils.POP_VLAN {
1324 actionInfo[PopVlan] = true
1325 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
1326 } else if action.Type == utils.PUSH_VLAN {
1327 if out := action.GetPush(); out != nil {
1328 if tpid := out.GetEthertype(); tpid != 0x8100 {
1329 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
1330 } else {
1331 actionInfo[PushVlan] = true
1332 actionInfo[TPID] = tpid
1333 log.Debugw("action-type-push-vlan",
1334 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
1335 }
1336 }
1337 } else if action.Type == utils.SET_FIELD {
1338 if out := action.GetSetField(); out != nil {
1339 if field := out.GetField(); field != nil {
1340 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
1341 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
1342 return
1343 }
1344 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
1345 if ofbField := field.GetOfbField(); ofbField != nil {
1346 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
1347 if vlan := ofbField.GetVlanVid(); vlan != 0 {
1348 actionInfo[VlanVid] = vlan & 0xfff
1349 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
1350 } else {
1351 log.Error("No Invalid vlan id in set vlan-vid action")
1352 }
1353 } else {
1354 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
1355 }
1356 }
1357 }
1358 }
1359 } else {
1360 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
1361 return
1362 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301363 }
manikkaraj k17652a72019-05-06 09:06:36 -04001364 /* Controller bound trap flows */
1365 if isControllerFlow := IsControllerBoundFlow(actionInfo[OUTPUT].(uint32)); isControllerFlow {
1366 log.Debug("Controller bound trap flows, getting inport from tunnelid")
1367 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001368 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001369 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001370 classifierInfo[InPort] = uniPort
1371 log.Debugw("upstream pon-to-controller-flow,inport-in-tunnelid", log.Fields{"newInPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
manikkaraj kbf256be2019-03-25 00:13:48 +05301372 } else {
manikkaraj k17652a72019-05-06 09:06:36 -04001373 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
1374 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301375 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001376 } /*else {
1377 log.Debugw("Trap on NNI flow currently not supported", log.Fields{"flow": *flow})
1378 return
1379 }*/
manikkaraj k17652a72019-05-06 09:06:36 -04001380 } else {
1381 log.Debug("Non-Controller flows, getting uniport from tunnelid")
1382 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001383 if portType := IntfIDToPortTypeName(actionInfo[OUTPUT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001384 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -04001385 actionInfo[OUTPUT] = uniPort
1386 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[OUTPUT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
1387 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001388 log.Debug("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid", log.Fields{"InPort": classifierInfo[InPort].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
manikkaraj k17652a72019-05-06 09:06:36 -04001389 return
1390 }
1391 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001392 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001393 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001394 classifierInfo[InPort] = uniPort
manikkaraj k17652a72019-05-06 09:06:36 -04001395 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[OUTPUT].(uint32),
1396 "outport": actionInfo[OUTPUT].(uint32)})
1397 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001398 log.Debug("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid", log.Fields{"InPort": classifierInfo[InPort].(uint32),
manikkaraj k17652a72019-05-06 09:06:36 -04001399 "outPort": actionInfo[OUTPUT].(uint32)})
1400 return
1401 }
1402 }
1403 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001404 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[OUTPUT]})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001405 portNo, intfId, onuId, uniId := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[OUTPUT].(uint32))
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001406 if ipProto, ok := classifierInfo[IPProto]; ok {
1407 if ipProto.(uint32) == IPProtoDhcp {
1408 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001409 if udpSrc.(uint32) == uint32(67) {
1410 log.Debug("trap-dhcp-from-nni-flow")
1411 f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
1412 return
1413 }
1414 }
1415 }
1416 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001417 /* Metadata 8 bytes:
1418 Most Significant 2 Bytes = Inner VLAN
1419 Next 2 Bytes = Tech Profile ID(TPID)
1420 Least Significant 4 Bytes = Port ID
1421 Flow METADATA carries Tech-Profile (TP) ID and is mandatory in all
1422 subscriber related flows.
1423 */
1424 metadata := utils.GetMetadataFromWriteMetadataAction(flow)
1425 if metadata == 0 {
1426 log.Error("Metadata is not present in flow which is mandatory")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001427 return
1428 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001429 TpID := utils.GetTechProfileIDFromWriteMetaData(metadata)
1430 kvstoreTpId := f.resourceMgr.GetTechProfileIdForOnu(intfId, onuId, uniId)
1431 if kvstoreTpId == 0 {
1432 log.Debugf("tpid-not-present-in-kvstore, using tp id %d from flow metadata", TpID)
1433 } else if kvstoreTpId != uint32(TpID) {
1434 log.Error(" Tech-profile-updates-not-supported", log.Fields{"Tpid-in-flow": TpID, "kvstore-TpId": kvstoreTpId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001435 return
1436 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001437 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfId, "onuId": onuId, "uniId": uniId})
1438 if IsUpstream(actionInfo[OUTPUT].(uint32)) {
1439 UsMeterID = utils.GetMeterIdFromFlow(flow)
1440 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1441 } else {
1442 DsMeterID = utils.GetMeterIdFromFlow(flow)
1443 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1444
1445 }
1446 f.divideAndAddFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001447}
1448
1449//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04001450func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001451
1452 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301453 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001454 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301455 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05301456 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301457 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04001458
Manikkaraj kb1d51442019-07-23 10:41:02 -04001459 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001460 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04001461 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
1462 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1463 tpDownloadMsg,
1464 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
1465 f.deviceHandler.deviceType,
1466 onuDevice.Type,
1467 onuDevice.Id,
1468 onuDevice.ProxyAddress.DeviceId, "")
1469 if sendErr != nil {
1470 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1471 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1472 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1473 return sendErr
1474 }
1475 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05301476 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301477}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001478
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001479//UpdateOnuInfo function adds onu info to cache
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001480func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001481 onu := onuInfo{intfID: intfID, onuID: onuID, serialNumber: serialNum}
1482 onuIDkey := onuIDKey{intfID: intfID, onuID: onuID}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001483 f.onuIds[onuIDkey] = onu
1484 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
1485}
1486
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001487//addGemPortToOnuInfoMap function stores adds GEMport to ONU map
1488func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfID uint32, onuID uint32, gemPort uint32) {
1489 onuIDkey := onuIDKey{intfID: intfID, onuID: onuID}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001490 if val, ok := f.onuIds[onuIDkey]; ok {
1491 onuInfo := val
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001492 gemportKey := gemPortKey{intfID: intfID, gemPort: gemPort}
1493 f.onuGemPortIds[gemportKey] = onuInfo
1494 log.Debugw("Cached Gemport to Onuinfo map", log.Fields{"GemPort": gemPort, "intfId": onuInfo.intfID, "onuId": onuInfo.onuID})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001495 return
1496 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001497 log.Errorw("OnuInfo not found", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001498}
1499
1500// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001501
1502//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
1503func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
1504 log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPortId": gemPortID})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001505 if serialNumber != "" {
1506 if onuInfo, ok := f.onuSerialNumbers[serialNumber]; ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001507 return onuInfo.onuID, nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001508 }
1509 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001510 gemportKey := gemPortKey{intfID: intfID, gemPort: gemPortID}
1511 if onuInfo, ok := f.onuGemPortIds[gemportKey]; ok {
1512 log.Debugw("Retrieved onu info from access", log.Fields{"intfId": intfID, "gemPortId": gemPortID, "onuId": onuInfo.onuID})
1513 return onuInfo.onuID, nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001514 }
1515 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001516 log.Errorw("onuid is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPort": gemPortID})
1517 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 -04001518}
1519
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001520//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
1521func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001522 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001523 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001524 var err error
1525
1526 if packetIn.IntfType == "pon" {
1527 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001528 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001529 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
1530 return logicalPortNum, err
1531 }
1532 if packetIn.PortNo != 0 {
1533 logicalPortNum = packetIn.PortNo
1534 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001535 uniID := uint32(0) // FIXME - multi-uni support
1536 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001537 }
1538 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001539 pktInkey := packetInInfoKey{intfID: packetIn.IntfId, onuID: onuID, logicalPort: logicalPortNum}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001540 f.packetInGemPort[pktInkey] = packetIn.GemportId
1541 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001542 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001543 }
1544 log.Debugw("Retrieved logicalport from packet-in", log.Fields{"logicalPortNum": logicalPortNum, "IntfType": packetIn.IntfType})
1545 return logicalPortNum, nil
1546}
1547
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001548//GetPacketOutGemPortID returns gemPortId
1549func (f *OpenOltFlowMgr) GetPacketOutGemPortID(intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
1550 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001551 var err error
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001552 key := packetInInfoKey{intfID: intfID, onuID: onuID, logicalPort: portNum}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001553 if val, ok := f.packetInGemPort[key]; ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001554 gemPortID = val
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001555 } else {
1556 log.Errorw("Key-Error while fetching packet-out GEM port", log.Fields{"key": key})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001557 err = errors.New("key-error while fetching packet-out GEM port")
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001558 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001559 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001560}
1561
Manikkaraj kb1d51442019-07-23 10:41:02 -04001562func installFlowOnAllGemports(
1563 f1 func(intfId uint32, onuId uint32, uniId uint32,
1564 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
1565 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32),
1566 f2 func(intfId uint32, onuId uint32, uniId uint32, portNo uint32,
1567 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32),
1568 args map[string]uint32,
1569 classifier map[string]interface{}, action map[string]interface{},
1570 logicalFlow *ofp.OfpFlowStats,
1571 gemPorts []uint32,
1572 FlowType string,
1573 vlanId ...uint32) {
1574 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanId})
1575 for _, gemPortId := range gemPorts {
1576 if FlowType == HsiaFlow || FlowType == DhcpFlow {
1577 f1(args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortId)
1578 } else if FlowType == EapolFlow {
1579 f2(args["intfId"], args["onuId"], args["uniId"], args["portNo"], logicalFlow, args["allocId"], gemPortId, vlanId[0])
1580 } else {
1581 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
1582 return
1583 }
1584 }
1585}
1586
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001587func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
1588 log.Debug("Adding trap-dhcp-of-nni-flow")
1589 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001590 classifier[PacketTagType] = DoubleTag
1591 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001592 /* We manage flowId resource pool on per PON port basis.
1593 Since this situation is tricky, as a hack, we pass the NNI port
1594 index (network_intf_id) as PON port Index for the flowId resource
1595 pool. Also, there is no ONU Id available for trapping DHCP packets
1596 on NNI port, use onu_id as -1 (invalid)
1597 ****************** CAVEAT *******************
1598 This logic works if the NNI Port Id falls within the same valid
1599 range of PON Port Ids. If this doesn't work for some OLT Vendor
1600 we need to have a re-look at this.
1601 *********************************************
1602 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001603 onuID := -1
1604 uniID := -1
1605 gemPortID := -1
1606 allocID := -1
1607 networkInterfaceID := f.deviceHandler.nniIntfID
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001608 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001609 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceID), uint32(onuID), uint32(uniID), flowStoreCookie); present {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001610 log.Debug("Flow-exists--not-re-adding")
1611 return
1612 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001613 flowID, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceID), uint32(onuID), uint32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001614 if err != nil {
1615 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
1616 return
1617 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001618 var classifierProto *openoltpb2.Classifier
1619 var actionProto *openoltpb2.Action
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001620 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
1621 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
1622 return
1623 }
1624 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1625 if actionProto = makeOpenOltActionField(action); actionProto == nil {
1626 log.Error("Error in making action protobuf for dhcp trap on nni flow")
1627 return
1628 }
1629 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001630 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1631 OnuId: int32(onuID), // OnuId not required
1632 UniId: int32(uniID), // UniId not used
1633 FlowId: flowID,
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001634 FlowType: DOWNSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001635 AllocId: int32(allocID), // AllocId not used
1636 NetworkIntfId: int32(networkInterfaceID),
1637 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001638 Classifier: classifierProto,
1639 Action: actionProto,
1640 Priority: int32(logicalFlow.Priority),
1641 Cookie: logicalFlow.Cookie,
1642 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001643 if ok := f.addFlowToDevice(logicalFlow, &downstreamflow); ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001644 log.Debug("DHCP trap on NNI flow added to device successfully")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001645 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowID)
1646 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceID),
1647 int32(onuID),
1648 int32(uniID),
1649 flowID, flowsToKVStore); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001650 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1651 }
1652 }
1653 return
1654}