blob: 38d5c7ec9e0c863ab1f5753e8a0bcb6798aabc85 [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"
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040037 //deepcopy "github.com/getlantern/deepcopy"
Daniele Rossi22db98e2019-07-11 11:50:00 +000038 "google.golang.org/grpc/codes"
39 "google.golang.org/grpc/status"
manikkaraj kbf256be2019-03-25 00:13:48 +053040)
41
42const (
43 // Flow categories
manikkaraj kbf256be2019-03-25 00:13:48 +053044
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070045 //HsiaFlow flow category
46 HsiaFlow = "HSIA_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053047
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070048 //EapolFlow flow category
49 EapolFlow = "EAPOL_FLOW"
manikkaraj kbf256be2019-03-25 00:13:48 +053050
Manikkaraj kb1d51442019-07-23 10:41:02 -040051 //DhcpFlow flow category
52 DhcpFlow = "DHCP_FLOW"
53
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070054 //IPProtoDhcp flow category
55 IPProtoDhcp = 17
manikkaraj kbf256be2019-03-25 00:13:48 +053056
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070057 //IPProtoIgmp flow category
58 IPProtoIgmp = 2
59
60 //EapEthType eapethtype value
61 EapEthType = 0x888e
62 //LldpEthType lldp ethtype value
63 LldpEthType = 0x88cc
64
65 //IgmpProto proto value
66 IgmpProto = 2
manikkaraj kbf256be2019-03-25 00:13:48 +053067
68 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070069
70 //DefaultMgmtVlan default vlan value
71 DefaultMgmtVlan = 4091
manikkaraj kbf256be2019-03-25 00:13:48 +053072
manikkaraj kbf256be2019-03-25 00:13:48 +053073 // Openolt Flow
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070074
75 //UPSTREAM constant
76 UPSTREAM = "upstream"
77 //DOWNSTREAM constant
78 DOWNSTREAM = "downstream"
79 //PacketTagType constant
80 PacketTagType = "pkt_tag_type"
81 //UNTAGGED constant
82 UNTAGGED = "untagged"
83 //SingleTag constant
84 SingleTag = "single_tag"
85 //DoubleTag constant
86 DoubleTag = "double_tag"
manikkaraj kbf256be2019-03-25 00:13:48 +053087
88 // classifierInfo
Girish Gowdru6a80bbd2019-07-02 07:36:09 -070089
90 //EthType constant
91 EthType = "eth_type"
92 //TPID constant
93 TPID = "tpid"
94 //IPProto constant
95 IPProto = "ip_proto"
96 //InPort constant
97 InPort = "in_port"
98 //VlanVid constant
99 VlanVid = "vlan_vid"
100 //VlanPcp constant
101 VlanPcp = "vlan_pcp"
102
103 //UDPDst constant
104 UDPDst = "udp_dst"
105 //UDPSrc constant
106 UDPSrc = "udp_src"
107 //Ipv4Dst constant
108 Ipv4Dst = "ipv4_dst"
109 //Ipv4Src constant
110 Ipv4Src = "ipv4_src"
111 //METADATA constant
112 METADATA = "metadata"
113 //TunnelID constant
114 TunnelID = "tunnel_id"
115 //OUTPUT constant
116 OUTPUT = "output"
117 // Actions
118
119 //PopVlan constant
120 PopVlan = "pop_vlan"
121 //PushVlan constant
122 PushVlan = "push_vlan"
123 //TrapToHost constant
124 TrapToHost = "trap_to_host"
Manikkaraj kb1d51442019-07-23 10:41:02 -0400125 //MaxMeterBand constant
126 MaxMeterBand = 2
127 //VlanPCPMask contant
128 VlanPCPMask = 0xFF
129 //VlanvIDMask constant
130 VlanvIDMask = 0xFFF
131 //MaxPonPorts constant
132 MaxPonPorts = 16
manikkaraj kbf256be2019-03-25 00:13:48 +0530133)
134
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400135type onuInfo struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700136 intfID uint32
137 onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400138 serialNumber string
139}
140
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700141type onuIDKey struct {
142 intfID uint32
143 onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400144}
145
146type gemPortKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700147 intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400148 gemPort uint32
149}
150
151type packetInInfoKey struct {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700152 intfID uint32
153 onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400154 logicalPort uint32
155}
156
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700157//OpenOltFlowMgr creates the Structure of OpenOltFlowMgr obj
manikkaraj kbf256be2019-03-25 00:13:48 +0530158type OpenOltFlowMgr struct {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400159 techprofile []*tp.TechProfileMgr
160 deviceHandler *DeviceHandler
161 resourceMgr *rsrcMgr.OpenOltResourceMgr
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700162 onuIds map[onuIDKey]onuInfo //OnuId -> OnuInfo
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400163 onuSerialNumbers map[string]onuInfo //onu serial_number (string) -> OnuInfo
164 onuGemPortIds map[gemPortKey]onuInfo //GemPortId -> OnuInfo
165 packetInGemPort map[packetInInfoKey]uint32 //packet in gem port
166 storedDeviceFlows []ofp.OfpFlowStats /* Required during deletion to obtain device flows from logical flows */
manikkaraj kbf256be2019-03-25 00:13:48 +0530167}
168
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700169//NewFlowManager creates OpenOltFlowMgr object and initializes the parameters
manikkaraj kbf256be2019-03-25 00:13:48 +0530170func NewFlowManager(dh *DeviceHandler, rsrcMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
171 log.Info("Initializing flow manager")
172 var flowMgr OpenOltFlowMgr
173 flowMgr.deviceHandler = dh
174 flowMgr.resourceMgr = rsrcMgr
Manikkaraj kb1d51442019-07-23 10:41:02 -0400175 flowMgr.techprofile = make([]*tp.TechProfileMgr, MaxPonPorts)
manikkaraj kbf256be2019-03-25 00:13:48 +0530176 if err := flowMgr.populateTechProfilePerPonPort(); err != nil {
177 log.Error("Error while populating tech profile mgr\n")
178 return nil
179 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700180 flowMgr.onuIds = make(map[onuIDKey]onuInfo)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400181 flowMgr.onuSerialNumbers = make(map[string]onuInfo)
182 flowMgr.onuGemPortIds = make(map[gemPortKey]onuInfo)
183 flowMgr.packetInGemPort = make(map[packetInInfoKey]uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530184 log.Info("Initialization of flow manager success!!")
185 return &flowMgr
186}
187
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700188func (f *OpenOltFlowMgr) generateStoredFlowID(flowID uint32, direction string) (uint64, error) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400189 if direction == UPSTREAM {
190 log.Debug("upstream flow, shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700191 return 0x1<<15 | uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400192 } else if direction == DOWNSTREAM {
193 log.Debug("downstream flow, not shifting id")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700194 return uint64(flowID), nil
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400195 } else {
196 log.Debug("Unrecognized direction")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700197 return 0, fmt.Errorf("unrecognized direction %s", direction)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400198 }
199}
200
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700201func (f *OpenOltFlowMgr) registerFlow(flowFromCore *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400202 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700203 log.Fields{"device": f.deviceHandler.deviceID})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400204
205 var storedFlow ofp.OfpFlowStats
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700206 storedFlow.Id, _ = f.generateStoredFlowID(deviceFlow.FlowId, deviceFlow.FlowType)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400207 log.Debug(fmt.Sprintf("Generated stored device flow. id = %d, flowId = %d, direction = %s", storedFlow.Id,
208 deviceFlow.FlowId, deviceFlow.FlowType))
209 storedFlow.Cookie = flowFromCore.Id
210 f.storedDeviceFlows = append(f.storedDeviceFlows, storedFlow)
211 log.Debugw("updated Stored flow info", log.Fields{"storedDeviceFlows": f.storedDeviceFlows})
212}
213
Manikkaraj kb1d51442019-07-23 10:41:02 -0400214func (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) {
215 var allocId []uint32
manikkaraj kbf256be2019-03-25 00:13:48 +0530216 var gemPorts []uint32
Manikkaraj kb1d51442019-07-23 10:41:02 -0400217 var gemPort uint32
218 var TpInst *tp.TechProfile
manikkaraj kbf256be2019-03-25 00:13:48 +0530219
Manikkaraj kb1d51442019-07-23 10:41:02 -0400220 log.Infow("Dividing flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "portNo": portNo,
221 "classifier": classifierInfo, "action": actionInfo, "UsMeterId": UsMeterId, "DsMeterId": DsMeterId, "TpId": TpId})
Matt Jeanneret77199612019-07-26 18:08:35 -0400222 // only create tcont/gemports if there is actually an onu id. otherwise BAL throws an error. Usually this
223 // is because the flow is an NNI flow and there would be no onu resources associated with it
224 // TODO: properly deal with NNI flows
Manikkaraj kb1d51442019-07-23 10:41:02 -0400225 if onuID <= 0 {
Matt Jeanneret77199612019-07-26 18:08:35 -0400226 log.Errorw("No onu id for flow", log.Fields{"portNo": portNo, "classifer": classifierInfo, "action": actionInfo})
manikkaraj kbf256be2019-03-25 00:13:48 +0530227 return
228 }
229
Manikkaraj kb1d51442019-07-23 10:41:02 -0400230 uni := getUniPortPath(intfID, onuID, uniID)
231 log.Debugw("Uni port name", log.Fields{"uni": uni})
232 allocId, gemPorts, TpInst = f.createTcontGemports(intfID, onuID, uniID, uni, portNo, TpId, UsMeterId, DsMeterId, flowMetadata)
233 if allocId == nil || gemPorts == nil || TpInst == nil {
234 log.Error("alloc-id-gem-ports-tp-unavailable")
235 return
236 }
237
238 /* Flows can be added specific to gemport if p-bits are received.
239 * If no pbit mentioned then adding flows for all gemports
manikkaraj kbf256be2019-03-25 00:13:48 +0530240 */
Manikkaraj kb1d51442019-07-23 10:41:02 -0400241
242 args := make(map[string]uint32)
243 args["intfId"] = intfID
244 args["onuId"] = onuID
245 args["uniId"] = uniID
246 args["portNo"] = portNo
247 args["allocId"] = allocId[0]
248
249 if ipProto, ok := classifierInfo[IPProto]; ok {
250 if ipProto.(uint32) == IPProtoDhcp {
251 log.Info("Adding DHCP flow")
252 if pcp, ok := classifierInfo[VlanPcp]; ok {
253 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
254 tp_pb.Direction_UPSTREAM,
255 pcp.(uint32))
256 //Adding DHCP upstream flow
257 f.addDHCPTrapFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
manikkaraj kbf256be2019-03-25 00:13:48 +0530258 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400259 //Adding DHCP upstream flow to all gemports
260 installFlowOnAllGemports(f.addDHCPTrapFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, DhcpFlow)
manikkaraj kbf256be2019-03-25 00:13:48 +0530261 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400262
263 } else if ipProto == IgmpProto {
264 log.Info("igmp flow add ignored, not implemented yet")
manikkaraj kbf256be2019-03-25 00:13:48 +0530265 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400266 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
267 //return errors.New("Invalid-Classifier-to-handle")
manikkaraj kbf256be2019-03-25 00:13:48 +0530268 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400269 } else if ethType, ok := classifierInfo[EthType]; ok {
270 if ethType.(uint32) == EapEthType {
271 log.Info("Adding EAPOL flow")
272 var vlanId uint32
273 if val, ok := classifierInfo[VlanVid]; ok {
274 vlanId = (val.(uint32)) & VlanvIDMask
275 } else {
276 vlanId = DefaultMgmtVlan
277 }
278 if pcp, ok := classifierInfo[VlanPcp]; ok {
279 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
280 tp_pb.Direction_UPSTREAM,
281 pcp.(uint32))
282
283 f.addEAPOLFlow(intfID, onuID, uniID, portNo, flow, allocId[0], gemPort, vlanId)
284 } else {
285 installFlowOnAllGemports(nil, f.addEAPOLFlow, args, classifierInfo, actionInfo, flow, gemPorts, EapolFlow, vlanId)
286 }
287 // Send Techprofile download event to child device in go routine as it takes time
288 go f.sendTPDownloadMsgToChild(intfID, onuID, uniID, uni, TpId)
289 }
290 if ethType == LldpEthType {
291 log.Info("Adding LLDP flow")
292 addLLDPFlow(flow, portNo)
293 }
294 } else if _, ok := actionInfo[PushVlan]; ok {
295 log.Info("Adding upstream data rule")
296 if pcp, ok := classifierInfo[VlanPcp]; ok {
297 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
298 tp_pb.Direction_UPSTREAM,
299 pcp.(uint32))
300 //Adding HSIA upstream flow
301 f.addUpstreamDataFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
302 } else {
303 //Adding HSIA upstream flow to all gemports
304 installFlowOnAllGemports(f.addUpstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
305 }
306 } else if _, ok := actionInfo[PopVlan]; ok {
307 log.Info("Adding Downstream data rule")
308 if pcp, ok := classifierInfo[VlanPcp]; ok {
309 gemPort = f.techprofile[intfID].GetGemportIDForPbit(TpInst,
310 tp_pb.Direction_UPSTREAM,
311 pcp.(uint32))
312 //Adding HSIA downstream flow
313 f.addDownstreamDataFlow(intfID, onuID, uniID, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
314 } else {
315 //Adding HSIA downstream flow to all gemports
316 installFlowOnAllGemports(f.addDownstreamDataFlow, nil, args, classifierInfo, actionInfo, flow, gemPorts, HsiaFlow)
317 }
318 } else {
319 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
manikkaraj kbf256be2019-03-25 00:13:48 +0530320 }
321}
322
Manikkaraj kb1d51442019-07-23 10:41:02 -0400323func (f *OpenOltFlowMgr) CreateSchedulerQueues(Dir tp_pb.Direction, IntfId uint32, OnuId uint32, UniId uint32, UniPort uint32, TpInst *tp.TechProfile, MeterId uint32, flowMetadata *voltha.FlowMetadata) error {
324
325 log.Debugw("CreateSchedulerQueues", log.Fields{"Dir": Dir, "IntfId": IntfId, "OnuId": OnuId,
326 "UniId": UniId, "MeterId": MeterId, "TpInst": *TpInst, "flowMetadata": flowMetadata})
327
328 if MeterId == 0 { // This should never happen
329 log.Error("Invalid meter id")
330 return errors.New("Invalid meter id")
331 }
332
333 /* Lets make a simple assumption that if the meter-id is present on the KV store,
334 * then the scheduler and queues configuration is applied on the OLT device
335 * in the given direction.
336 */
337 var Direction string
338 var SchedCfg *tp_pb.SchedulerConfig
339 if Dir == tp_pb.Direction_UPSTREAM {
340 Direction = "upstream"
341 } else if Dir == tp_pb.Direction_DOWNSTREAM {
342 Direction = "downstream"
343 }
344 KvStoreMeter, err := f.resourceMgr.GetMeterIdForOnu(Direction, IntfId, OnuId, UniId)
345 if err != nil {
346 log.Error("Failed to get meter for intf %d, onuid %d, uniid %d", IntfId, OnuId, UniId)
347 return err
348 }
349 if KvStoreMeter != nil {
350 if KvStoreMeter.MeterId == MeterId {
351 log.Debug("Scheduler already created for upstream")
352 return nil
353 } else {
354 log.Errorw("Dynamic meter update not supported", log.Fields{"KvStoreMeterId": KvStoreMeter.MeterId, "MeterId-in-flow": MeterId})
355 return errors.New("Invalid-meter-id-in-flow")
356 }
357 }
358 log.Debugw("Meter-does-not-exist-Creating-new", log.Fields{"MeterId": MeterId, "Direction": Direction})
359 if Dir == tp_pb.Direction_UPSTREAM {
360 SchedCfg = f.techprofile[IntfId].GetUsScheduler(TpInst)
361 } else if Dir == tp_pb.Direction_DOWNSTREAM {
362 SchedCfg = f.techprofile[IntfId].GetDsScheduler(TpInst)
363 }
364 var meterConfig *ofp.OfpMeterConfig
365 if flowMetadata != nil {
366 for _, meter := range flowMetadata.Meters {
367 if MeterId == meter.MeterId {
368 meterConfig = meter
369 log.Debugw("Found-meter-config-from-flowmetadata", log.Fields{"meterConfig": meterConfig})
370 break
371 }
372 }
373 } else {
374 log.Error("Flow-metadata-is-not-present-in-flow")
375 }
376 if meterConfig == nil {
377 log.Errorw("Could-not-get-meterbands-from-flowMetadata", log.Fields{"flowMetadata": flowMetadata, "MeterId": MeterId})
378 return errors.New("Failed-to-get-meter-from-flowMetadata")
379 } else if len(meterConfig.Bands) < MaxMeterBand {
380 log.Errorw("Invalid-number-of-bands-in-meter", log.Fields{"Bands": meterConfig.Bands, "MeterId": MeterId})
381 return errors.New("Invalid-number-of-bands-in-meter")
382 }
383 cir := meterConfig.Bands[0].Rate
384 cbs := meterConfig.Bands[0].BurstSize
385 eir := meterConfig.Bands[1].Rate
386 ebs := meterConfig.Bands[1].BurstSize
387 pir := cir + eir
388 pbs := cbs + ebs
389 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
390
391 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[IntfId].GetTrafficScheduler(TpInst, SchedCfg, TrafficShaping)}
392
393 log.Debugw("Sending Traffic scheduler create to device", log.Fields{"Direction": Direction, "TrafficScheds": TrafficSched})
394 if _, err := f.deviceHandler.Client.CreateTrafficSchedulers(context.Background(), &tp_pb.TrafficSchedulers{
395 IntfId: IntfId, OnuId: OnuId,
396 UniId: UniId, PortNo: UniPort,
397 TrafficScheds: TrafficSched}); err != nil {
398 log.Errorw("Failed to create traffic schedulers", log.Fields{"error": err})
399 return err
400 }
401 // On receiving the CreateTrafficQueues request, the driver should create corresponding
402 // downstream queues.
403 trafficQueues := f.techprofile[IntfId].GetTrafficQueues(TpInst, Dir)
404 log.Debugw("Sending Traffic Queues create to device", log.Fields{"Direction": Direction, "TrafficQueues": trafficQueues})
405 if _, err := f.deviceHandler.Client.CreateTrafficQueues(context.Background(),
406 &tp_pb.TrafficQueues{IntfId: IntfId, OnuId: OnuId,
407 UniId: UniId, PortNo: UniPort,
408 TrafficQueues: trafficQueues}); err != nil {
409 log.Errorw("Failed to create traffic queues in device", log.Fields{"error": err})
410 return err
411 }
412
413 /* After we succesfully applied the scheduler configuration on the OLT device,
414 * store the meter id on the KV store, for further reference.
415 */
416 if err := f.resourceMgr.UpdateMeterIdForOnu(Direction, IntfId, OnuId, UniId, meterConfig); err != nil {
417 log.Error("Failed to update meter id for onu %d, meterid %d", OnuId, MeterId)
418 return err
419 }
420 log.Debugw("updated-meter-info into KV store successfully", log.Fields{"Direction": Direction,
421 "Meter": meterConfig})
422 return nil
423}
424
425func (f *OpenOltFlowMgr) RemoveSchedulerQueues(Dir tp_pb.Direction, IntfId uint32, OnuId uint32, UniId uint32, UniPort uint32, TpInst *tp.TechProfile) error {
426
427 var Direction string
428 var SchedCfg *tp_pb.SchedulerConfig
429 var err error
430 log.Debugw("Removing schedulers and Queues in OLT", log.Fields{"Direction": Dir, "IntfId": IntfId, "OnuId": OnuId, "UniId": UniId, "UniPort": UniPort})
431 if Dir == tp_pb.Direction_UPSTREAM {
432 SchedCfg = f.techprofile[IntfId].GetUsScheduler(TpInst)
433 Direction = "upstream"
434 } else if Dir == tp_pb.Direction_DOWNSTREAM {
435 SchedCfg = f.techprofile[IntfId].GetDsScheduler(TpInst)
436 Direction = "downstream"
437 }
438
439 KVStoreMeter, err := f.resourceMgr.GetMeterIdForOnu(Direction, IntfId, OnuId, UniId)
440 if err != nil {
441 log.Errorf("Failed to get Meter for Onu %d", OnuId)
442 return err
443 }
444 if KVStoreMeter == nil {
445 log.Debugw("No-meter-has-been-installed-yet", log.Fields{"direction": Direction, "IntfId": IntfId, "OnuId": OnuId, "UniId": UniId})
446 return nil
447 }
448 cir := KVStoreMeter.Bands[0].Rate
449 cbs := KVStoreMeter.Bands[0].BurstSize
450 eir := KVStoreMeter.Bands[1].Rate
451 ebs := KVStoreMeter.Bands[1].BurstSize
452 pir := cir + eir
453 pbs := cbs + ebs
454
455 TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
456
457 TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[IntfId].GetTrafficScheduler(TpInst, SchedCfg, TrafficShaping)}
458 TrafficQueues := f.techprofile[IntfId].GetTrafficQueues(TpInst, Dir)
459
460 if _, err = f.deviceHandler.Client.RemoveTrafficQueues(context.Background(),
461 &tp_pb.TrafficQueues{IntfId: IntfId, OnuId: OnuId,
462 UniId: UniId, PortNo: UniPort,
463 TrafficQueues: TrafficQueues}); err != nil {
464 log.Error("Failed to remove traffic queues")
465 return err
466 } else {
467 log.Debug("Removed traffic queues successfully")
468 }
469 if _, err = f.deviceHandler.Client.RemoveTrafficSchedulers(context.Background(), &tp_pb.TrafficSchedulers{
470 IntfId: IntfId, OnuId: OnuId,
471 UniId: UniId, PortNo: UniPort,
472 TrafficScheds: TrafficSched}); err != nil {
473 log.Error("failed to remove traffic schedulers")
474 return err
475 } else {
476 log.Debug("Removed traffic schedulers successfully")
477 }
478
479 /* After we succesfully remove the scheduler configuration on the OLT device,
480 * delete the meter id on the KV store.
481 */
482 err = f.resourceMgr.RemoveMeterIdForOnu(Direction, IntfId, OnuId, UniId)
483 if err != nil {
484 log.Errorf("Failed to remove meter for onu %d, meter id %d", OnuId, KVStoreMeter.MeterId)
485 }
486 log.Debugw("Removed-meter-from-KV-store successfully", log.Fields{"MeterId": KVStoreMeter.MeterId, "dir": Direction})
487 return err
488}
489
manikkaraj kbf256be2019-03-25 00:13:48 +0530490// This function allocates tconts and GEM ports for an ONU, currently one TCONT is supported per ONU
Manikkaraj kb1d51442019-07-23 10:41:02 -0400491func (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 +0530492 var allocID []uint32
493 var gemPortIDs []uint32
494 //If we already have allocated earlier for this onu, render them
Manikkaraj kb1d51442019-07-23 10:41:02 -0400495 if tcontId := f.resourceMgr.GetCurrentAllocIDForOnu(intfID, onuID, uniID); tcontId != 0 {
496 allocID = append(allocID, tcontId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530497 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700498 gemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(intfID, onuID, uniID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400499
500 tpPath := f.getTPpath(intfID, uni, TpID)
501 // Check tech profile instance already exists for derived port name
502 tech_profile_instance, err := f.techprofile[intfID].GetTPInstanceFromKVStore(TpID, tpPath)
503 if err != nil { // This should not happen, something wrong in KV backend transaction
504 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": TpID, "path": tpPath})
505 return nil, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530506 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400507
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700508 log.Debug("Creating New TConts and Gem ports", log.Fields{"pon": intfID, "onu": onuID, "uni": uniID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530509
Manikkaraj kb1d51442019-07-23 10:41:02 -0400510 if tech_profile_instance == nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530511 log.Info("Creating tech profile instance", log.Fields{"path": tpPath})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400512 tech_profile_instance = f.techprofile[intfID].CreateTechProfInstance(TpID, uni, intfID)
513 if tech_profile_instance == nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530514 log.Error("Tech-profile-instance-creation-failed")
Manikkaraj kb1d51442019-07-23 10:41:02 -0400515 return nil, nil, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530516 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400517 f.resourceMgr.UpdateTechProfileIdForOnu(intfID, onuID, uniID, TpID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530518 } else {
519 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
520 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400521 if UsMeterID != 0 {
522 if err := f.CreateSchedulerQueues(tp_pb.Direction_UPSTREAM, intfID, onuID, uniID, uniPort, tech_profile_instance, UsMeterID, flowMetadata); err != nil {
523 log.Errorw("CreateSchedulerQueues Failed-upstream", log.Fields{"error": err, "meterID": UsMeterID})
524 return nil, nil, nil
525 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530526 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400527 if DsMeterID != 0 {
528 if err := f.CreateSchedulerQueues(tp_pb.Direction_DOWNSTREAM, intfID, onuID, uniID, uniPort, tech_profile_instance, DsMeterID, flowMetadata); err != nil {
529 log.Errorw("CreateSchedulerQueues Failed-downstream", log.Fields{"error": err, "meterID": DsMeterID})
530 return nil, nil, nil
531 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530532 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400533 if len(allocID) == 0 { // Created TCONT first time
534 allocID = append(allocID, tech_profile_instance.UsScheduler.AllocID)
535 }
536 if len(gemPortIDs) == 0 { // Create GEM ports first time
537 for _, gem := range tech_profile_instance.UpstreamGemPortAttributeList {
538 gemPortIDs = append(gemPortIDs, gem.GemportID)
539 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530540 }
541 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocID": allocID, "gemports": gemPortIDs})
542 // Send Tconts and GEM ports to KV store
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700543 f.storeTcontsGEMPortsIntoKVStore(intfID, onuID, uniID, allocID, gemPortIDs)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400544 return allocID, gemPortIDs, tech_profile_instance
manikkaraj kbf256be2019-03-25 00:13:48 +0530545}
546
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700547func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(intfID uint32, onuID uint32, uniID uint32, allocID []uint32, gemPortIDs []uint32) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530548
549 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700550 log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "allocID": allocID, "gemPortIDs": gemPortIDs})
manikkaraj kbf256be2019-03-25 00:13:48 +0530551 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700552 if err := f.resourceMgr.UpdateAllocIdsForOnu(intfID, onuID, uniID, allocID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530553 log.Error("Errow while uploading allocID to KV store")
554 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700555 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(intfID, onuID, uniID, gemPortIDs); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530556 log.Error("Errow while uploading GEMports to KV store")
557 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700558 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(gemPortIDs, intfID, onuID, uniID); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530559 log.Error("Errow while uploading gemtopon map to KV store")
560 }
561 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400562 for _, gemPort := range gemPortIDs {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700563 f.addGemPortToOnuInfoMap(intfID, onuID, gemPort)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400564 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530565}
566
567func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400568 var tpCount int = 0
manikkaraj kbf256be2019-03-25 00:13:48 +0530569 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400570 for _, intfId := range techRange.IntfIds {
571 f.techprofile[intfId] = f.resourceMgr.ResourceMgrs[uint32(intfId)].TechProfileMgr
572 tpCount++
573 log.Debugw("Init tech profile done", log.Fields{"intfId": intfId})
manikkaraj kbf256be2019-03-25 00:13:48 +0530574 }
575 }
576 //Make sure we have as many tech_profiles as there are pon ports on the device
Manikkaraj kb1d51442019-07-23 10:41:02 -0400577 if tpCount != int(f.resourceMgr.DevInfo.GetPonPorts()) {
manikkaraj kbf256be2019-03-25 00:13:48 +0530578 log.Errorw("Error while populating techprofile",
Manikkaraj kb1d51442019-07-23 10:41:02 -0400579 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
580 return errors.New("Error while populating techprofile mgrs")
manikkaraj kbf256be2019-03-25 00:13:48 +0530581 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400582 log.Infow("Populated techprofile for ponports successfully",
583 log.Fields{"numofTech": tpCount, "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
manikkaraj kbf256be2019-03-25 00:13:48 +0530584 return nil
585}
586
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700587func (f *OpenOltFlowMgr) addUpstreamDataFlow(intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530588 portNo uint32, uplinkClassifier map[string]interface{},
589 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700590 allocID uint32, gemportID uint32) {
591 uplinkClassifier[PacketTagType] = SingleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530592 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700593 f.addHSIAFlow(intfID, onuID, uniID, portNo, uplinkClassifier, uplinkAction,
594 UPSTREAM, logicalFlow, allocID, gemportID)
Manikkaraj k884c1242019-04-11 16:26:42 +0530595 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530596}
597
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700598func (f *OpenOltFlowMgr) addDownstreamDataFlow(intfID uint32, onuID uint32, uniID uint32,
Manikkaraj k884c1242019-04-11 16:26:42 +0530599 portNo uint32, downlinkClassifier map[string]interface{},
600 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700601 allocID uint32, gemportID uint32) {
602 downlinkClassifier[PacketTagType] = DoubleTag
Manikkaraj k884c1242019-04-11 16:26:42 +0530603 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
604 "downlinkAction": downlinkAction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400605 // Ignore Downlink trap flow given by core, cannot do anything with this flow */
606 if vlan, exists := downlinkClassifier[VlanVid]; exists {
607 if vlan.(uint32) == (uint32(ofp.OfpVlanId_OFPVID_PRESENT) | 4000) { //private VLAN given by core
608 if metadata, exists := downlinkClassifier[METADATA]; exists { // inport is filled in metadata by core
609 if uint32(metadata.(uint64)) == MkUniPortNum(intfID, onuID, uniID) {
610 log.Infow("Ignoring DL trap device flow from core", log.Fields{"flow": logicalFlow})
611 return
612 }
613 }
614 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530615 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400616
Manikkaraj k884c1242019-04-11 16:26:42 +0530617 /* Already this info available classifier? */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700618 downlinkAction[PopVlan] = true
619 downlinkAction[VlanVid] = downlinkClassifier[VlanVid]
620 f.addHSIAFlow(intfID, onuID, uniID, portNo, downlinkClassifier, downlinkAction,
621 DOWNSTREAM, logicalFlow, allocID, gemportID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530622}
623
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700624func (f *OpenOltFlowMgr) addHSIAFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, classifier map[string]interface{},
Manikkaraj k884c1242019-04-11 16:26:42 +0530625 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700626 allocID uint32, gemPortID uint32) {
Manikkaraj k884c1242019-04-11 16:26:42 +0530627 /* One of the OLT platform (Broadcom BAL) requires that symmetric
628 flows require the same flow_id to be used across UL and DL.
629 Since HSIA flow is the only symmetric flow currently, we need to
630 re-use the flow_id across both direction. The 'flow_category'
631 takes priority over flow_cookie to find any available HSIA_FLOW
632 id for the ONU.
633 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700634 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfID, "onuId": onuID, "uniId": uniID, "classifier": classifier,
635 "action": action, "direction": direction, "allocId": allocID, "gemPortId": gemPortID,
Manikkaraj k884c1242019-04-11 16:26:42 +0530636 "logicalFlow": *logicalFlow})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400637 var vlan_pit uint32 = 0
638 if _, ok := classifier[VlanPcp]; ok {
639 vlan_pit = classifier[VlanPcp].(uint32)
640 log.Debugw("Found pbit in the flow", log.Fields{"vlan_pit": vlan_pit})
641 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700642 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400643 flowId, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, HsiaFlow, vlan_pit)
Manikkaraj k884c1242019-04-11 16:26:42 +0530644 if err != nil {
645 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
646 return
647 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700648 var classifierProto *openoltpb2.Classifier
649 var actionProto *openoltpb2.Action
Manikkaraj k884c1242019-04-11 16:26:42 +0530650 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
651 log.Error("Error in making classifier protobuf for hsia flow")
652 return
653 }
654 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
655 if actionProto = makeOpenOltActionField(action); actionProto == nil {
656 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
657 return
658 }
659 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700660 networkIntfID := f.deviceHandler.nniIntfID
661 flow := openoltpb2.Flow{AccessIntfId: int32(intfID),
662 OnuId: int32(onuID),
663 UniId: int32(uniID),
Manikkaraj kb1d51442019-07-23 10:41:02 -0400664 FlowId: flowId,
Manikkaraj k884c1242019-04-11 16:26:42 +0530665 FlowType: direction,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700666 AllocId: int32(allocID),
667 NetworkIntfId: int32(networkIntfID),
668 GemportId: int32(gemPortID),
Manikkaraj k884c1242019-04-11 16:26:42 +0530669 Classifier: classifierProto,
670 Action: actionProto,
671 Priority: int32(logicalFlow.Priority),
672 Cookie: logicalFlow.Cookie,
673 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400674 if ok := f.addFlowToDevice(logicalFlow, &flow); ok {
Manikkaraj k884c1242019-04-11 16:26:42 +0530675 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
Manikkaraj kb1d51442019-07-23 10:41:02 -0400676 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, HsiaFlow, flowId)
Manikkaraj k884c1242019-04-11 16:26:42 +0530677 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
678 flow.OnuId,
679 flow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400680 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530681 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
682 return
683 }
684 }
685}
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700686func (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 +0530687
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700688 var dhcpFlow openoltpb2.Flow
689 var actionProto *openoltpb2.Action
690 var classifierProto *openoltpb2.Classifier
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530691
692 // Clear the action map
693 for k := range action {
694 delete(action, k)
695 }
696
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700697 action[TrapToHost] = true
698 classifier[UDPSrc] = uint32(68)
699 classifier[UDPDst] = uint32(67)
700 classifier[PacketTagType] = SingleTag
701 delete(classifier, VlanVid)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530702
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700703 flowStoreCookie := getFlowStoreCookie(classifier, gemPortID)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530704
Manikkaraj kb1d51442019-07-23 10:41:02 -0400705 flowID, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, "", 0 /*classifier[VLAN_PCP].(uint32)*/)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530706
707 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700708 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530709 return
710 }
711
712 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
713
714 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
715 log.Error("Error in making classifier protobuf for ul flow")
716 return
717 }
718 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
719 if actionProto = makeOpenOltActionField(action); actionProto == nil {
720 log.Error("Error in making action protobuf for ul flow")
721 return
722 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700723 networkIntfID := f.deviceHandler.nniIntfID
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530724
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700725 dhcpFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
726 OnuId: int32(onuID),
727 UniId: int32(uniID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530728 FlowId: flowID,
729 FlowType: UPSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700730 AllocId: int32(allocID),
731 NetworkIntfId: int32(networkIntfID),
732 GemportId: int32(gemPortID),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530733 Classifier: classifierProto,
734 Action: actionProto,
735 Priority: int32(logicalFlow.Priority),
736 Cookie: logicalFlow.Cookie,
737 PortNo: portNo}
738
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400739 if ok := f.addFlowToDevice(logicalFlow, &dhcpFlow); ok {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530740 log.Debug("DHCP UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400741 flowsToKVStore := f.getUpdatedFlowInfo(&dhcpFlow, flowStoreCookie, "DHCP", flowID)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530742 if err := f.updateFlowInfoToKVStore(dhcpFlow.AccessIntfId,
743 dhcpFlow.OnuId,
744 dhcpFlow.UniId,
745 dhcpFlow.FlowId, flowsToKVStore); err != nil {
746 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
747 return
748 }
749 }
750
manikkaraj kbf256be2019-03-25 00:13:48 +0530751 return
752}
753
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700754// Add EAPOL flow to device with mac, vlanId as classifier for upstream and downstream
755func (f *OpenOltFlowMgr) addEAPOLFlow(intfID uint32, onuID uint32, uniID uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocID uint32, gemPortID uint32, vlanID uint32) {
756 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 +0530757
758 uplinkClassifier := make(map[string]interface{})
759 uplinkAction := make(map[string]interface{})
760 downlinkClassifier := make(map[string]interface{})
761 downlinkAction := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700762 var upstreamFlow openoltpb2.Flow
763 var downstreamFlow openoltpb2.Flow
manikkaraj kbf256be2019-03-25 00:13:48 +0530764
765 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700766 uplinkClassifier[EthType] = uint32(EapEthType)
767 uplinkClassifier[PacketTagType] = SingleTag
768 uplinkClassifier[VlanVid] = vlanID
manikkaraj kbf256be2019-03-25 00:13:48 +0530769 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700770 uplinkAction[TrapToHost] = true
771 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530772 //Add Uplink EAPOL Flow
Manikkaraj kb1d51442019-07-23 10:41:02 -0400773 uplinkFlowID, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530774 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700775 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
Manikkaraj k884c1242019-04-11 16:26:42 +0530776 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530777 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700778 var classifierProto *openoltpb2.Classifier
779 var actionProto *openoltpb2.Action
780 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowID})
manikkaraj kbf256be2019-03-25 00:13:48 +0530781
782 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
783 log.Error("Error in making classifier protobuf for ul flow")
784 return
785 }
786 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
787 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
788 log.Error("Error in making action protobuf for ul flow")
789 return
790 }
791 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700792 networkIntfID := f.deviceHandler.nniIntfID
793 upstreamFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
794 OnuId: int32(onuID),
795 UniId: int32(uniID),
796 FlowId: uplinkFlowID,
manikkaraj kbf256be2019-03-25 00:13:48 +0530797 FlowType: UPSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700798 AllocId: int32(allocID),
799 NetworkIntfId: int32(networkIntfID),
800 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +0530801 Classifier: classifierProto,
802 Action: actionProto,
803 Priority: int32(logicalFlow.Priority),
804 Cookie: logicalFlow.Cookie,
805 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400806 if ok := f.addFlowToDevice(logicalFlow, &upstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530807 log.Debug("EAPOL UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400808 flowCategory := "EAPOL"
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700809 flowsToKVStore := f.getUpdatedFlowInfo(&upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowID)
manikkaraj kbf256be2019-03-25 00:13:48 +0530810 if err := f.updateFlowInfoToKVStore(upstreamFlow.AccessIntfId,
811 upstreamFlow.OnuId,
812 upstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400813 upstreamFlow.FlowId,
814 /* lowCategory, */
815 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530816 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
817 return
818 }
819 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400820 // Dummy Downstream flow due to BAL 2.6 limitation
821 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530822 /* Add Downstream EAPOL Flow, Only for first EAP flow (BAL
823 # requirement)
824 # On one of the platforms (Broadcom BAL), when same DL classifier
825 # vlan was used across multiple ONUs, eapol flow re-adds after
826 # flow delete (cases of onu reboot/disable) fails.
827 # In order to generate unique vlan, a combination of intf_id
828 # onu_id and uniId is used.
829 # uniId defaults to 0, so add 1 to it.
830 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700831 log.Debugw("Creating DL EAPOL flow with default vlan", log.Fields{"vlan": vlanID})
832 specialVlanDlFlow := 4090 - intfID*onuID*(uniID+1)
manikkaraj kbf256be2019-03-25 00:13:48 +0530833 // Assert that we do not generate invalid vlans under no condition
834 if specialVlanDlFlow <= 2 {
835 log.Fatalw("invalid-vlan-generated", log.Fields{"vlan": specialVlanDlFlow})
836 return
837 }
838 log.Debugw("specialVlanEAPOLDlFlow:", log.Fields{"dl_vlan": specialVlanDlFlow})
839 // Fill Classfier
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700840 downlinkClassifier[PacketTagType] = SingleTag
Manikkaraj kb1d51442019-07-23 10:41:02 -0400841 downlinkClassifier[EthType] = uint32(EapEthType)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700842 downlinkClassifier[VlanVid] = uint32(specialVlanDlFlow)
manikkaraj kbf256be2019-03-25 00:13:48 +0530843 // Fill action
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700844 downlinkAction[PushVlan] = true
845 downlinkAction[VlanVid] = vlanID
846 flowStoreCookie := getFlowStoreCookie(downlinkClassifier, gemPortID)
Manikkaraj kb1d51442019-07-23 10:41:02 -0400847 downlinkFlowId, err := f.resourceMgr.GetFlowID(intfID, onuID, uniID, gemPortID, flowStoreCookie, "", 0)
manikkaraj kbf256be2019-03-25 00:13:48 +0530848 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530849 log.Errorw("flowId unavailable for DL EAPOL",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700850 log.Fields{"intfId": intfID, "onuId": onuID, "flowStoreCookie": flowStoreCookie})
manikkaraj kbf256be2019-03-25 00:13:48 +0530851 return
852 }
853 log.Debugw("Creating DL EAPOL flow",
Manikkaraj kb1d51442019-07-23 10:41:02 -0400854 log.Fields{"dl_classifier": downlinkClassifier, "dl_action": downlinkAction, "downlinkFlowId": downlinkFlowId})
manikkaraj kbf256be2019-03-25 00:13:48 +0530855 if classifierProto = makeOpenOltClassifierField(downlinkClassifier); classifierProto == nil {
856 log.Error("Error in making classifier protobuf for downlink flow")
857 return
858 }
859 if actionProto = makeOpenOltActionField(downlinkAction); actionProto == nil {
860 log.Error("Error in making action protobuf for dl flow")
861 return
862 }
863 // Downstream flow in grpc protobuf
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700864 downstreamFlow = openoltpb2.Flow{AccessIntfId: int32(intfID),
865 OnuId: int32(onuID),
866 UniId: int32(uniID),
Manikkaraj kb1d51442019-07-23 10:41:02 -0400867 FlowId: downlinkFlowId,
manikkaraj kbf256be2019-03-25 00:13:48 +0530868 FlowType: DOWNSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700869 AllocId: int32(allocID),
870 NetworkIntfId: int32(networkIntfID),
871 GemportId: int32(gemPortID),
manikkaraj kbf256be2019-03-25 00:13:48 +0530872 Classifier: classifierProto,
873 Action: actionProto,
874 Priority: int32(logicalFlow.Priority),
875 Cookie: logicalFlow.Cookie,
876 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400877 if ok := f.addFlowToDevice(logicalFlow, &downstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530878 log.Debug("EAPOL DL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400879 flowCategory := ""
Manikkaraj kb1d51442019-07-23 10:41:02 -0400880 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamFlow, flowStoreCookie, flowCategory, downlinkFlowId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530881 if err := f.updateFlowInfoToKVStore(downstreamFlow.AccessIntfId,
882 downstreamFlow.OnuId,
883 downstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400884 downstreamFlow.FlowId,
885 /* flowCategory, */
886 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530887 log.Errorw("Error uploading EAPOL DL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
888 return
889 }
890 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530891 }
892 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
893}
894
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700895func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openoltpb2.Classifier {
896 var classifier openoltpb2.Classifier
897 if etherType, ok := classifierInfo[EthType]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530898 classifier.EthType = etherType.(uint32)
899 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700900 if ipProto, ok := classifierInfo[IPProto]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530901 classifier.IpProto = ipProto.(uint32)
902 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700903 if vlanID, ok := classifierInfo[VlanVid]; ok {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400904 classifier.OVid = (vlanID.(uint32)) & VlanvIDMask
manikkaraj kbf256be2019-03-25 00:13:48 +0530905 }
Manikkaraj kb1d51442019-07-23 10:41:02 -0400906 if metadata, ok := classifierInfo[METADATA]; ok {
Manikkaraj k884c1242019-04-11 16:26:42 +0530907 classifier.IVid = uint32(metadata.(uint64))
manikkaraj kbf256be2019-03-25 00:13:48 +0530908 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700909 if vlanPcp, ok := classifierInfo[VlanPcp]; ok {
Manikkaraj kb1d51442019-07-23 10:41:02 -0400910 if vlanPcp == 0 {
911 classifier.OPbits = VlanPCPMask
912 } else {
913 classifier.OPbits = (vlanPcp.(uint32)) & VlanPCPMask
914 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530915 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700916 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530917 classifier.SrcPort = udpSrc.(uint32)
918 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700919 if udpDst, ok := classifierInfo[UDPDst]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530920 classifier.DstPort = udpDst.(uint32)
921 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700922 if ipv4Dst, ok := classifierInfo[Ipv4Dst]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530923 classifier.DstIp = ipv4Dst.(uint32)
924 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700925 if ipv4Src, ok := classifierInfo[Ipv4Src]; ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530926 classifier.SrcIp = ipv4Src.(uint32)
927 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700928 if pktTagType, ok := classifierInfo[PacketTagType]; ok {
929 if pktTagType.(string) == SingleTag {
930 classifier.PktTagType = SingleTag
931 } else if pktTagType.(string) == DoubleTag {
932 classifier.PktTagType = DoubleTag
manikkaraj kbf256be2019-03-25 00:13:48 +0530933 } else if pktTagType.(string) == UNTAGGED {
934 classifier.PktTagType = UNTAGGED
935 } else {
936 log.Error("Invalid tag type in classifier") // should not hit
937 return nil
938 }
939 }
940 return &classifier
941}
942
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700943func makeOpenOltActionField(actionInfo map[string]interface{}) *openoltpb2.Action {
944 var actionCmd openoltpb2.ActionCmd
945 var action openoltpb2.Action
manikkaraj kbf256be2019-03-25 00:13:48 +0530946 action.Cmd = &actionCmd
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700947 if _, ok := actionInfo[PopVlan]; ok {
948 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530949 action.Cmd.RemoveOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700950 } else if _, ok := actionInfo[PushVlan]; ok {
951 action.OVid = actionInfo[VlanVid].(uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530952 action.Cmd.AddOuterTag = true
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700953 } else if _, ok := actionInfo[TrapToHost]; ok {
954 action.Cmd.TrapToHost = actionInfo[TrapToHost].(bool)
manikkaraj kbf256be2019-03-25 00:13:48 +0530955 } else {
956 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
957 return nil
958 }
959 return &action
960}
961
Manikkaraj kb1d51442019-07-23 10:41:02 -0400962func (f *OpenOltFlowMgr) getTPpath(intfID uint32, uni string, TpID uint32) string {
963 return f.techprofile[intfID].GetTechProfileInstanceKVPath(TpID, uni)
manikkaraj kbf256be2019-03-25 00:13:48 +0530964}
965
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700966func getFlowStoreCookie(classifier map[string]interface{}, gemPortID uint32) uint64 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530967 if len(classifier) == 0 { // should never happen
968 log.Error("Invalid classfier object")
969 return 0
970 }
971 var jsonData []byte
972 var flowString string
973 var err error
974 // TODO: Do we need to marshall ??
975 if jsonData, err = json.Marshal(classifier); err != nil {
976 log.Error("Failed to encode classifier")
977 return 0
978 }
979 flowString = string(jsonData)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700980 if gemPortID != 0 {
981 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortID))
manikkaraj kbf256be2019-03-25 00:13:48 +0530982 }
983 h := md5.New()
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700984 _, _ = h.Write([]byte(flowString))
manikkaraj kbf256be2019-03-25 00:13:48 +0530985 hash := big.NewInt(0)
986 hash.SetBytes(h.Sum(nil))
987 return hash.Uint64()
988}
989
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700990func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openoltpb2.Flow, flowStoreCookie uint64, flowCategory string, deviceFlowID uint32) *[]rsrcMgr.FlowInfo {
991 var flows = []rsrcMgr.FlowInfo{{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
992 var intfID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400993 /* For flows which trap out of the NNI, the AccessIntfId is invalid
994 (set to -1). In such cases, we need to refer to the NetworkIntfId .
995 */
996 if flow.AccessIntfId != -1 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700997 intfID = uint32(flow.AccessIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400998 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -0700999 intfID = uint32(flow.NetworkIntfId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001000 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001001 // Get existing flows matching flowid for given subscriber from KV store
1002 existingFlows := f.resourceMgr.GetFlowIDInfo(intfID, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -04001003 if existingFlows != nil {
1004 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001005 //for _, f := range *existingFlows {
1006 // flows = append(flows, f)
1007 //}
1008 flows = append(flows, *existingFlows...)
manikkaraj k17652a72019-05-06 09:06:36 -04001009 }
1010 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 +05301011 return &flows
1012}
1013
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001014//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
1015// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
1016// var intfId uint32
1017// /* For flows which trap out of the NNI, the AccessIntfId is invalid
1018// (set to -1). In such cases, we need to refer to the NetworkIntfId .
1019// */
1020// if flow.AccessIntfId != -1 {
1021// intfId = uint32(flow.AccessIntfId)
1022// } else {
1023// intfId = uint32(flow.NetworkIntfId)
1024// }
1025// // Get existing flows matching flowid for given subscriber from KV store
1026// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
1027// if existingFlows != nil {
1028// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
1029// for _, f := range *existingFlows {
1030// flows = append(flows, f)
1031// }
1032// }
1033// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
1034// return &flows
1035//}
1036
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001037func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(intfID int32, onuID int32, uniID int32, flowID uint32, flows *[]rsrcMgr.FlowInfo) error {
manikkaraj k17652a72019-05-06 09:06:36 -04001038 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001039 if err := f.resourceMgr.UpdateFlowIDInfo(intfID, onuID, uniID, flowID, flows); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -04001040 log.Debug("Error while Storing flow into KV store")
1041 return err
1042 }
1043 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +05301044 return nil
1045}
1046
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001047func (f *OpenOltFlowMgr) addFlowToDevice(logicalFlow *ofp.OfpFlowStats, deviceFlow *openoltpb2.Flow) bool {
Daniele Rossi22db98e2019-07-11 11:50:00 +00001048
1049 var intfID uint32
1050 /* For flows which trap out of the NNI, the AccessIntfId is invalid
1051 (set to -1). In such cases, we need to refer to the NetworkIntfId .
1052 */
1053 if deviceFlow.AccessIntfId != -1 {
1054 intfID = uint32(deviceFlow.AccessIntfId)
1055 } else {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001056 // REVIST : Why ponport is given as network port?
Daniele Rossi22db98e2019-07-11 11:50:00 +00001057 intfID = uint32(deviceFlow.NetworkIntfId)
1058 }
1059
manikkaraj kbf256be2019-03-25 00:13:48 +05301060 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1061 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
Daniele Rossi22db98e2019-07-11 11:50:00 +00001062
1063 st, _ := status.FromError(err)
1064 if st.Code() == codes.AlreadyExists {
1065 log.Debug("Flow already exixts", log.Fields{"err": err, "deviceFlow": deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +05301066 return false
1067 }
Daniele Rossi22db98e2019-07-11 11:50:00 +00001068
1069 if err != nil {
1070 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
1071 f.resourceMgr.FreeFlowID(intfID, uint32(deviceFlow.OnuId), uint32(deviceFlow.UniId), deviceFlow.FlowId)
1072 return false
1073 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001074 log.Debugw("Flow added to device successfully ", log.Fields{"flow": *deviceFlow})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001075 f.registerFlow(logicalFlow, deviceFlow)
1076 return true
1077}
1078
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001079func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openoltpb2.Flow) bool {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001080 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
1081 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
1082 if err != nil {
1083 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
1084 return false
1085 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001086 log.Debugw("Flow removed from device successfully ", log.Fields{"flow": *deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +05301087 return true
1088}
1089
1090/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
1091 //update core flows_proxy : flows_proxy.update('/', flows)
1092}
1093
1094func generateStoredId(flowId uint32, direction string)uint32{
1095
1096 if direction == UPSTREAM{
1097 log.Debug("Upstream flow shifting flowid")
1098 return ((0x1 << 15) | flowId)
1099 }else if direction == DOWNSTREAM{
1100 log.Debug("Downstream flow not shifting flowid")
1101 return flowId
1102 }else{
1103 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
1104 return flowId
1105 }
1106}
1107
1108*/
1109
1110func addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001111 log.Info("unimplemented flow : %v, portNo : %v ", flow, portNo)
manikkaraj kbf256be2019-03-25 00:13:48 +05301112}
1113
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001114func getUniPortPath(intfID uint32, onuID uint32, uniID uint32) string {
1115 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfID, onuID, uniID)
1116}
1117
1118//getOnuChildDevice to fetch onu
1119func (f *OpenOltFlowMgr) getOnuChildDevice(intfID uint32, onuID uint32) (*voltha.Device, error) {
1120 log.Debugw("GetChildDevice", log.Fields{"pon port": intfID, "onuId": onuID})
1121 parentPortNo := IntfIDToPortNo(intfID, voltha.Port_PON_OLT)
1122 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301123 if onuDevice == nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001124 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301125 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +05301126 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301127 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
1128 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301129}
1130
1131func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001132 log.Info("unimplemented flow : %v", flow)
manikkaraj kbf256be2019-03-25 00:13:48 +05301133 return nil
1134}
1135
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001136func (f *OpenOltFlowMgr) clearFlowsAndSchedulerForLogicalPort(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
1137 log.Info("unimplemented device %v, logicalport %v", childDevice, logicalPort)
manikkaraj kbf256be2019-03-25 00:13:48 +05301138}
1139
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001140func (f *OpenOltFlowMgr) decodeStoredID(id uint64) (uint64, string) {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001141 if id>>15 == 0x1 {
1142 return id & 0x7fff, UPSTREAM
1143 }
1144 return id, DOWNSTREAM
1145}
1146
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001147func (f *OpenOltFlowMgr) clearFlowFromResourceManager(flow *ofp.OfpFlowStats, flowID uint32, flowDirection string) {
1148 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowID": flowID, "flowDirection": flowDirection, "flow": *flow})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001149 portNum, ponIntf, onuID, uniID, err := FlowExtractInfo(flow, flowDirection)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001150 if err != nil {
1151 log.Error(err)
1152 return
1153 }
1154 log.Debugw("Extracted access info from flow to be deleted",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001155 log.Fields{"ponIntf": ponIntf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001156
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001157 flowsInfo := f.resourceMgr.GetFlowIDInfo(ponIntf, onuID, uniID, flowID)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001158 if flowsInfo == nil {
1159 log.Debugw("No FlowInfo found found in KV store",
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001160 log.Fields{"ponIntf": ponIntf, "onuID": onuID, "uniID": uniID, "flowID": flowID})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001161 return
1162 }
1163 var updatedFlows []rsrcMgr.FlowInfo
1164
1165 for _, flow := range *flowsInfo {
1166 updatedFlows = append(updatedFlows, flow)
1167 }
1168
1169 for i, storedFlow := range updatedFlows {
1170 if flowDirection == storedFlow.Flow.FlowType {
1171 //Remove the Flow from FlowInfo
1172 log.Debugw("Removing flow to be deleted", log.Fields{"flow": storedFlow})
1173 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
1174 break
1175 }
1176 }
1177
1178 if len(updatedFlows) >= 0 {
1179 // There are still flows referencing the same flow_id.
1180 // So the flow should not be freed yet.
1181 // For ex: Case of HSIA where same flow is shared
1182 // between DS and US.
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001183 f.updateFlowInfoToKVStore(int32(ponIntf), int32(onuID), int32(uniID), flowID, &updatedFlows)
Manikkaraj kb1d51442019-07-23 10:41:02 -04001184 if len(updatedFlows) == 0 {
1185 log.Debugw("Releasing flow Id to resource manager", log.Fields{"ponIntf": ponIntf, "onuId": onuID, "uniId": uniID, "flowId": flowID})
1186 f.resourceMgr.FreeFlowID(ponIntf, onuID, uniID, flowID)
1187 }
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001188 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001189 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ponIntf, onuID, uniID)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001190 if len(flowIds) == 0 {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001191 log.Debugf("Flow count for subscriber %d is zero", onuID)
1192 kvstoreTpId := f.resourceMgr.GetTechProfileIdForOnu(ponIntf, onuID, uniID)
1193 if kvstoreTpId == 0 {
1194 log.Warnw("Could-not-find-techprofile-tableid-for-uni", log.Fields{"ponIntf": ponIntf, "onuId": onuID, "uniId": uniID})
1195 return
1196 }
1197 uni := getUniPortPath(ponIntf, onuID, uniID)
1198 tpPath := f.getTPpath(ponIntf, uni, kvstoreTpId)
1199 log.Debugw("Getting-techprofile-instance-for-subscriber", log.Fields{"TP-PATH": tpPath})
1200 techprofileInst, err := f.techprofile[ponIntf].GetTPInstanceFromKVStore(kvstoreTpId, tpPath)
1201 if err != nil { // This should not happen, something wrong in KV backend transaction
1202 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tpID": 20, "path": tpPath})
1203 return
1204 }
1205 if techprofileInst == nil {
1206 log.Errorw("Tech-profile-instance-does-not-exist-in-KV Store", log.Fields{"tpPath": tpPath})
1207 return
1208 }
1209
1210 f.RemoveSchedulerQueues(tp_pb.Direction_UPSTREAM, ponIntf, onuID, uniID, portNum, techprofileInst)
1211 f.RemoveSchedulerQueues(tp_pb.Direction_DOWNSTREAM, ponIntf, onuID, uniID, portNum, techprofileInst)
1212 } else {
1213 log.Debugf("Flow ids for subscriber", log.Fields{"onu": onuID, "flows": flowIds})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001214 }
1215}
1216
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001217//RemoveFlow removes the flow from the device
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001218func (f *OpenOltFlowMgr) RemoveFlow(flow *ofp.OfpFlowStats) {
1219 log.Debugw("Removing Flow", log.Fields{"flow": flow})
1220 var deviceFlowsToRemove []ofp.OfpFlowStats
1221 var deletedFlowsIdx []int
1222 for _, curFlow := range f.storedDeviceFlows {
1223 if curFlow.Cookie == flow.Id {
1224 log.Debugw("Found found matching flow-cookie", log.Fields{"curFlow": curFlow})
1225 deviceFlowsToRemove = append(deviceFlowsToRemove, curFlow)
1226 }
1227 }
1228 log.Debugw("Flows to be deleted", log.Fields{"deviceFlowsToRemove": deviceFlowsToRemove})
1229 for index, curFlow := range deviceFlowsToRemove {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001230 id, direction := f.decodeStoredID(curFlow.GetId())
1231 removeFlowMessage := openoltpb2.Flow{FlowId: uint32(id), FlowType: direction}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001232 if ok := f.removeFlowFromDevice(&removeFlowMessage); ok {
1233 log.Debug("Flow removed from device successfully")
1234 deletedFlowsIdx = append(deletedFlowsIdx, index)
1235 f.clearFlowFromResourceManager(flow, uint32(id), direction) //TODO: Take care of the limitations
1236 }
1237
1238 }
1239 // Can be done in separate go routine as it takes time ?
1240 for _, flowToRemove := range deletedFlowsIdx {
1241 for index, storedFlow := range f.storedDeviceFlows {
1242 if deviceFlowsToRemove[flowToRemove].Cookie == storedFlow.Cookie {
1243 log.Debugw("Removing flow from local Store", log.Fields{"flow": storedFlow})
1244 f.storedDeviceFlows = append(f.storedDeviceFlows[:index], f.storedDeviceFlows[index+1:]...)
1245 break
1246 }
1247 }
1248 }
1249 log.Debugw("Flows removed from the data store",
1250 log.Fields{"number_of_flows_removed": len(deviceFlowsToRemove), "updated_stored_flows": f.storedDeviceFlows})
1251 return
1252}
1253
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001254// AddFlow add flow to device
Manikkaraj kb1d51442019-07-23 10:41:02 -04001255func (f *OpenOltFlowMgr) AddFlow(flow *ofp.OfpFlowStats, flowMetadata *voltha.FlowMetadata) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001256 classifierInfo := make(map[string]interface{})
1257 actionInfo := make(map[string]interface{})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001258 var UsMeterID uint32
1259 var DsMeterID uint32
1260
1261 log.Debug("Adding Flow", log.Fields{"flow": flow, "flowMetadata": flowMetadata})
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001262 for _, field := range utils.GetOfbFields(flow) {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001263 if field.Type == utils.ETH_TYPE {
1264 classifierInfo[EthType] = field.GetEthType()
1265 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[EthType].(uint32)})
1266 } else if field.Type == utils.IP_PROTO {
1267 classifierInfo[IPProto] = field.GetIpProto()
1268 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IPProto].(uint32)})
1269 } else if field.Type == utils.IN_PORT {
1270 classifierInfo[InPort] = field.GetPort()
1271 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[InPort].(uint32)})
1272 } else if field.Type == utils.VLAN_VID {
1273 classifierInfo[VlanVid] = field.GetVlanVid()
1274 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VlanVid].(uint32)})
1275 } else if field.Type == utils.VLAN_PCP {
1276 classifierInfo[VlanPcp] = field.GetVlanPcp()
1277 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VlanPcp].(uint32)})
1278 } else if field.Type == utils.UDP_DST {
1279 classifierInfo[UDPDst] = field.GetUdpDst()
1280 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDPDst].(uint32)})
1281 } else if field.Type == utils.UDP_SRC {
1282 classifierInfo[UDPSrc] = field.GetUdpSrc()
1283 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDPSrc].(uint32)})
1284 } else if field.Type == utils.IPV4_DST {
1285 classifierInfo[Ipv4Dst] = field.GetIpv4Dst()
1286 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[Ipv4Dst].(uint32)})
1287 } else if field.Type == utils.IPV4_SRC {
1288 classifierInfo[Ipv4Src] = field.GetIpv4Src()
1289 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[Ipv4Src].(uint32)})
1290 } else if field.Type == utils.METADATA {
1291 classifierInfo[METADATA] = field.GetTableMetadata()
1292 log.Debug("field-type-metadata", log.Fields{"classifierInfo[METADATA]": classifierInfo[METADATA].(uint64)})
1293 } else if field.Type == utils.TUNNEL_ID {
1294 classifierInfo[TunnelID] = field.GetTunnelId()
1295 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TunnelID].(uint64)})
1296 } else {
1297 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
1298 return
1299 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301300 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001301 for _, action := range utils.GetActions(flow) {
Manikkaraj kb1d51442019-07-23 10:41:02 -04001302 if action.Type == utils.OUTPUT {
1303 if out := action.GetOutput(); out != nil {
1304 actionInfo[OUTPUT] = out.GetPort()
1305 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[OUTPUT].(uint32)})
1306 } else {
1307 log.Error("Invalid output port in action")
1308 return
1309 }
1310 } else if action.Type == utils.POP_VLAN {
1311 actionInfo[PopVlan] = true
1312 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[InPort].(uint32)})
1313 } else if action.Type == utils.PUSH_VLAN {
1314 if out := action.GetPush(); out != nil {
1315 if tpid := out.GetEthertype(); tpid != 0x8100 {
1316 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PushVlan].(int32)})
1317 } else {
1318 actionInfo[PushVlan] = true
1319 actionInfo[TPID] = tpid
1320 log.Debugw("action-type-push-vlan",
1321 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[InPort].(uint32)})
1322 }
1323 }
1324 } else if action.Type == utils.SET_FIELD {
1325 if out := action.GetSetField(); out != nil {
1326 if field := out.GetField(); field != nil {
1327 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
1328 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
1329 return
1330 }
1331 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
1332 if ofbField := field.GetOfbField(); ofbField != nil {
1333 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
1334 if vlan := ofbField.GetVlanVid(); vlan != 0 {
1335 actionInfo[VlanVid] = vlan & 0xfff
1336 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VlanVid].(uint32)})
1337 } else {
1338 log.Error("No Invalid vlan id in set vlan-vid action")
1339 }
1340 } else {
1341 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
1342 }
1343 }
1344 }
1345 }
1346 } else {
1347 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
1348 return
1349 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301350 }
manikkaraj k17652a72019-05-06 09:06:36 -04001351 /* Controller bound trap flows */
1352 if isControllerFlow := IsControllerBoundFlow(actionInfo[OUTPUT].(uint32)); isControllerFlow {
1353 log.Debug("Controller bound trap flows, getting inport from tunnelid")
1354 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001355 if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001356 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001357 classifierInfo[InPort] = uniPort
1358 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 +05301359 } else {
manikkaraj k17652a72019-05-06 09:06:36 -04001360 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
1361 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301362 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001363 } /*else {
1364 log.Debugw("Trap on NNI flow currently not supported", log.Fields{"flow": *flow})
1365 return
1366 }*/
manikkaraj k17652a72019-05-06 09:06:36 -04001367 } else {
1368 log.Debug("Non-Controller flows, getting uniport from tunnelid")
1369 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001370 if portType := IntfIDToPortTypeName(actionInfo[OUTPUT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001371 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -04001372 actionInfo[OUTPUT] = uniPort
1373 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[OUTPUT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
1374 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001375 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 -04001376 return
1377 }
1378 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001379 } else if portType := IntfIDToPortTypeName(classifierInfo[InPort].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001380 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001381 classifierInfo[InPort] = uniPort
manikkaraj k17652a72019-05-06 09:06:36 -04001382 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[OUTPUT].(uint32),
1383 "outport": actionInfo[OUTPUT].(uint32)})
1384 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001385 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 -04001386 "outPort": actionInfo[OUTPUT].(uint32)})
1387 return
1388 }
1389 }
1390 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001391 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[InPort], "action_output": actionInfo[OUTPUT]})
Manikkaraj kb1d51442019-07-23 10:41:02 -04001392 portNo, intfId, onuId, uniId := ExtractAccessFromFlow(classifierInfo[InPort].(uint32), actionInfo[OUTPUT].(uint32))
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001393 if ipProto, ok := classifierInfo[IPProto]; ok {
1394 if ipProto.(uint32) == IPProtoDhcp {
1395 if udpSrc, ok := classifierInfo[UDPSrc]; ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001396 if udpSrc.(uint32) == uint32(67) {
1397 log.Debug("trap-dhcp-from-nni-flow")
1398 f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
1399 return
1400 }
1401 }
1402 }
1403 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001404 /* Metadata 8 bytes:
1405 Most Significant 2 Bytes = Inner VLAN
1406 Next 2 Bytes = Tech Profile ID(TPID)
1407 Least Significant 4 Bytes = Port ID
1408 Flow METADATA carries Tech-Profile (TP) ID and is mandatory in all
1409 subscriber related flows.
1410 */
1411 metadata := utils.GetMetadataFromWriteMetadataAction(flow)
1412 if metadata == 0 {
1413 log.Error("Metadata is not present in flow which is mandatory")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001414 return
1415 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001416 TpID := utils.GetTechProfileIDFromWriteMetaData(metadata)
1417 kvstoreTpId := f.resourceMgr.GetTechProfileIdForOnu(intfId, onuId, uniId)
1418 if kvstoreTpId == 0 {
1419 log.Debugf("tpid-not-present-in-kvstore, using tp id %d from flow metadata", TpID)
1420 } else if kvstoreTpId != uint32(TpID) {
1421 log.Error(" Tech-profile-updates-not-supported", log.Fields{"Tpid-in-flow": TpID, "kvstore-TpId": kvstoreTpId})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001422 return
1423 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001424 log.Debugw("TPID for this subcriber", log.Fields{"TpId": TpID, "pon": intfId, "onuId": onuId, "uniId": uniId})
1425 if IsUpstream(actionInfo[OUTPUT].(uint32)) {
1426 UsMeterID = utils.GetMeterIdFromFlow(flow)
1427 log.Debugw("Upstream-flow-meter-id", log.Fields{"UsMeterID": UsMeterID})
1428 } else {
1429 DsMeterID = utils.GetMeterIdFromFlow(flow)
1430 log.Debugw("Downstream-flow-meter-id", log.Fields{"DsMeterID": DsMeterID})
1431
1432 }
1433 f.divideAndAddFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, uint32(TpID), UsMeterID, DsMeterID, flowMetadata)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001434}
1435
1436//sendTPDownloadMsgToChild send payload
Manikkaraj kb1d51442019-07-23 10:41:02 -04001437func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfID uint32, onuID uint32, uniID uint32, uni string, TpID uint32) error {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001438
1439 onuDevice, err := f.getOnuChildDevice(intfID, onuID)
Manikkaraj k884c1242019-04-11 16:26:42 +05301440 if err != nil {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001441 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuID})
Manikkaraj k884c1242019-04-11 16:26:42 +05301442 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05301443 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301444 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04001445
Manikkaraj kb1d51442019-07-23 10:41:02 -04001446 tpPath := f.getTPpath(intfID, uni, TpID)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001447 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniID, Path: tpPath}
manikkaraj k17652a72019-05-06 09:06:36 -04001448 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
1449 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1450 tpDownloadMsg,
1451 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
1452 f.deviceHandler.deviceType,
1453 onuDevice.Type,
1454 onuDevice.Id,
1455 onuDevice.ProxyAddress.DeviceId, "")
1456 if sendErr != nil {
1457 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1458 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1459 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1460 return sendErr
1461 }
1462 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05301463 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301464}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001465
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001466//UpdateOnuInfo function adds onu info to cache
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001467func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001468 onu := onuInfo{intfID: intfID, onuID: onuID, serialNumber: serialNum}
1469 onuIDkey := onuIDKey{intfID: intfID, onuID: onuID}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001470 f.onuIds[onuIDkey] = onu
1471 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
1472}
1473
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001474//addGemPortToOnuInfoMap function stores adds GEMport to ONU map
1475func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfID uint32, onuID uint32, gemPort uint32) {
1476 onuIDkey := onuIDKey{intfID: intfID, onuID: onuID}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001477 if val, ok := f.onuIds[onuIDkey]; ok {
1478 onuInfo := val
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001479 gemportKey := gemPortKey{intfID: intfID, gemPort: gemPort}
1480 f.onuGemPortIds[gemportKey] = onuInfo
1481 log.Debugw("Cached Gemport to Onuinfo map", log.Fields{"GemPort": gemPort, "intfId": onuInfo.intfID, "onuId": onuInfo.onuID})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001482 return
1483 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001484 log.Errorw("OnuInfo not found", log.Fields{"intfId": intfID, "onuId": onuID, "gemPort": gemPort})
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001485}
1486
1487// This function Lookup maps by serialNumber or (intfId, gemPort)
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001488
1489//getOnuIDfromGemPortMap Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
1490func (f *OpenOltFlowMgr) getOnuIDfromGemPortMap(serialNumber string, intfID uint32, gemPortID uint32) (uint32, error) {
1491 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 -04001492 if serialNumber != "" {
1493 if onuInfo, ok := f.onuSerialNumbers[serialNumber]; ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001494 return onuInfo.onuID, nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001495 }
1496 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001497 gemportKey := gemPortKey{intfID: intfID, gemPort: gemPortID}
1498 if onuInfo, ok := f.onuGemPortIds[gemportKey]; ok {
1499 log.Debugw("Retrieved onu info from access", log.Fields{"intfId": intfID, "gemPortId": gemPortID, "onuId": onuInfo.onuID})
1500 return onuInfo.onuID, nil
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001501 }
1502 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001503 log.Errorw("onuid is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfID, "gemPort": gemPortID})
1504 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 -04001505}
1506
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001507//GetLogicalPortFromPacketIn function computes logical port UNI/NNI port from packet-in indication and returns the same
1508func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openoltpb2.PacketIndication) (uint32, error) {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001509 var logicalPortNum uint32
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001510 var onuID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001511 var err error
1512
1513 if packetIn.IntfType == "pon" {
1514 // packet indication does not have serial number , so sending as nil
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001515 if onuID, err = f.getOnuIDfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001516 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
1517 return logicalPortNum, err
1518 }
1519 if packetIn.PortNo != 0 {
1520 logicalPortNum = packetIn.PortNo
1521 } else {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001522 uniID := uint32(0) // FIXME - multi-uni support
1523 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuID, uniID)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001524 }
1525 // 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 -07001526 pktInkey := packetInInfoKey{intfID: packetIn.IntfId, onuID: onuID, logicalPort: logicalPortNum}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001527 f.packetInGemPort[pktInkey] = packetIn.GemportId
1528 } else if packetIn.IntfType == "nni" {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001529 logicalPortNum = IntfIDToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001530 }
1531 log.Debugw("Retrieved logicalport from packet-in", log.Fields{"logicalPortNum": logicalPortNum, "IntfType": packetIn.IntfType})
1532 return logicalPortNum, nil
1533}
1534
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001535//GetPacketOutGemPortID returns gemPortId
1536func (f *OpenOltFlowMgr) GetPacketOutGemPortID(intfID uint32, onuID uint32, portNum uint32) (uint32, error) {
1537 var gemPortID uint32
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001538 var err error
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001539 key := packetInInfoKey{intfID: intfID, onuID: onuID, logicalPort: portNum}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001540 if val, ok := f.packetInGemPort[key]; ok {
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001541 gemPortID = val
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001542 } else {
1543 log.Errorw("Key-Error while fetching packet-out GEM port", log.Fields{"key": key})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001544 err = errors.New("key-error while fetching packet-out GEM port")
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001545 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001546 return gemPortID, err
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001547}
1548
Manikkaraj kb1d51442019-07-23 10:41:02 -04001549func installFlowOnAllGemports(
1550 f1 func(intfId uint32, onuId uint32, uniId uint32,
1551 portNo uint32, classifier map[string]interface{}, action map[string]interface{},
1552 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32),
1553 f2 func(intfId uint32, onuId uint32, uniId uint32, portNo uint32,
1554 logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32),
1555 args map[string]uint32,
1556 classifier map[string]interface{}, action map[string]interface{},
1557 logicalFlow *ofp.OfpFlowStats,
1558 gemPorts []uint32,
1559 FlowType string,
1560 vlanId ...uint32) {
1561 log.Debugw("Installing flow on all GEM ports", log.Fields{"FlowType": FlowType, "gemPorts": gemPorts, "vlan": vlanId})
1562 for _, gemPortId := range gemPorts {
1563 if FlowType == HsiaFlow || FlowType == DhcpFlow {
1564 f1(args["intfId"], args["onuId"], args["uniId"], args["portNo"], classifier, action, logicalFlow, args["allocId"], gemPortId)
1565 } else if FlowType == EapolFlow {
1566 f2(args["intfId"], args["onuId"], args["uniId"], args["portNo"], logicalFlow, args["allocId"], gemPortId, vlanId[0])
1567 } else {
1568 log.Errorw("Unrecognized Flow Type", log.Fields{"FlowType": FlowType})
1569 return
1570 }
1571 }
1572}
1573
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001574func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
1575 log.Debug("Adding trap-dhcp-of-nni-flow")
1576 action := make(map[string]interface{})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001577 classifier[PacketTagType] = DoubleTag
1578 action[TrapToHost] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001579 /* We manage flowId resource pool on per PON port basis.
1580 Since this situation is tricky, as a hack, we pass the NNI port
1581 index (network_intf_id) as PON port Index for the flowId resource
1582 pool. Also, there is no ONU Id available for trapping DHCP packets
1583 on NNI port, use onu_id as -1 (invalid)
1584 ****************** CAVEAT *******************
1585 This logic works if the NNI Port Id falls within the same valid
1586 range of PON Port Ids. If this doesn't work for some OLT Vendor
1587 we need to have a re-look at this.
1588 *********************************************
1589 */
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001590 onuID := -1
1591 uniID := -1
1592 gemPortID := -1
1593 allocID := -1
1594 networkInterfaceID := f.deviceHandler.nniIntfID
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001595 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001596 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceID), uint32(onuID), uint32(uniID), flowStoreCookie); present {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001597 log.Debug("Flow-exists--not-re-adding")
1598 return
1599 }
Manikkaraj kb1d51442019-07-23 10:41:02 -04001600 flowID, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceID), uint32(onuID), uint32(uniID), uint32(gemPortID), flowStoreCookie, "", 0)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001601 if err != nil {
1602 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
1603 return
1604 }
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001605 var classifierProto *openoltpb2.Classifier
1606 var actionProto *openoltpb2.Action
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001607 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
1608 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
1609 return
1610 }
1611 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1612 if actionProto = makeOpenOltActionField(action); actionProto == nil {
1613 log.Error("Error in making action protobuf for dhcp trap on nni flow")
1614 return
1615 }
1616 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001617 downstreamflow := openoltpb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1618 OnuId: int32(onuID), // OnuId not required
1619 UniId: int32(uniID), // UniId not used
1620 FlowId: flowID,
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001621 FlowType: DOWNSTREAM,
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001622 AllocId: int32(allocID), // AllocId not used
1623 NetworkIntfId: int32(networkInterfaceID),
1624 GemportId: int32(gemPortID), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001625 Classifier: classifierProto,
1626 Action: actionProto,
1627 Priority: int32(logicalFlow.Priority),
1628 Cookie: logicalFlow.Cookie,
1629 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001630 if ok := f.addFlowToDevice(logicalFlow, &downstreamflow); ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001631 log.Debug("DHCP trap on NNI flow added to device successfully")
Girish Gowdru6a80bbd2019-07-02 07:36:09 -07001632 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowID)
1633 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceID),
1634 int32(onuID),
1635 int32(uniID),
1636 flowID, flowsToKVStore); err != nil {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001637 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1638 }
1639 }
1640 return
1641}