blob: 570fff6b9dab4929bf8bc0cc0867373637083223 [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
17package adaptercore
18
19import (
20 "context"
21 "crypto/md5"
22 "encoding/json"
23 "errors"
24 "fmt"
manikkaraj kbf256be2019-03-25 00:13:48 +053025 "github.com/opencord/voltha-go/common/log"
26 tp "github.com/opencord/voltha-go/common/techprofile"
Matt Jeannereta93dbed2019-05-17 12:40:05 -040027 "github.com/opencord/voltha-go/rw_core/utils"
Manikkaraj k884c1242019-04-11 16:26:42 +053028 rsrcMgr "github.com/opencord/voltha-openolt-adapter/adaptercore/resourcemanager"
manikkaraj k17652a72019-05-06 09:06:36 -040029 ic "github.com/opencord/voltha-protos/go/inter_container"
manikkaraj kbf256be2019-03-25 00:13:48 +053030 ofp "github.com/opencord/voltha-protos/go/openflow_13"
31 openolt_pb2 "github.com/opencord/voltha-protos/go/openolt"
32 voltha "github.com/opencord/voltha-protos/go/voltha"
manikkaraj k17652a72019-05-06 09:06:36 -040033 "math/big"
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -040034 //deepcopy "github.com/getlantern/deepcopy"
manikkaraj kbf256be2019-03-25 00:13:48 +053035)
36
37const (
38 // Flow categories
39 HSIA_FLOW = "HSIA_FLOW"
40 EAPOL_FLOW = "EAPOL_FLOW"
41
42 IP_PROTO_DHCP = 17
43
44 IP_PROTO_IGMP = 2
45
46 EAP_ETH_TYPE = 0x888e
47 LLDP_ETH_TYPE = 0x88cc
48
49 IGMP_PROTO = 2
50
51 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
52 DEFAULT_MGMT_VLAN = 4091
53
manikkaraj kbf256be2019-03-25 00:13:48 +053054 // Openolt Flow
55 UPSTREAM = "upstream"
56 DOWNSTREAM = "downstream"
57 PACKET_TAG_TYPE = "pkt_tag_type"
58 UNTAGGED = "untagged"
59 SINGLE_TAG = "single_tag"
60 DOUBLE_TAG = "double_tag"
61
62 // classifierInfo
manikkaraj k17652a72019-05-06 09:06:36 -040063 ETH_TYPE = "eth_type"
64 TPID = "tpid"
65 IP_PROTO = "ip_proto"
66 IN_PORT = "in_port"
67 VLAN_VID = "vlan_vid"
68 VLAN_PCP = "vlan_pcp"
69 UDP_DST = "udp_dst"
70 UDP_SRC = "udp_src"
71 IPV4_DST = "ipv4_dst"
72 IPV4_SRC = "ipv4_src"
73 METADATA = "metadata"
74 TUNNEL_ID = "tunnel_id"
75 OUTPUT = "output"
manikkaraj kbf256be2019-03-25 00:13:48 +053076 // Action
77 POP_VLAN = "pop_vlan"
78 PUSH_VLAN = "push_vlan"
79 TRAP_TO_HOST = "trap_to_host"
80)
81
manikkaraj k9eb6cac2019-05-09 12:32:03 -040082type onuInfo struct {
83 intfId uint32
84 onuId uint32
85 serialNumber string
86}
87
88type onuIdKey struct {
89 intfId uint32
90 onuId uint32
91}
92
93type gemPortKey struct {
94 intfId uint32
95 gemPort uint32
96}
97
98type packetInInfoKey struct {
99 intfId uint32
100 onuId uint32
101 logicalPort uint32
102}
103
manikkaraj kbf256be2019-03-25 00:13:48 +0530104type OpenOltFlowMgr struct {
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400105 techprofile []*tp.TechProfileMgr
106 deviceHandler *DeviceHandler
107 resourceMgr *rsrcMgr.OpenOltResourceMgr
108 onuIds map[onuIdKey]onuInfo //OnuId -> OnuInfo
109 onuSerialNumbers map[string]onuInfo //onu serial_number (string) -> OnuInfo
110 onuGemPortIds map[gemPortKey]onuInfo //GemPortId -> OnuInfo
111 packetInGemPort map[packetInInfoKey]uint32 //packet in gem port
112 storedDeviceFlows []ofp.OfpFlowStats /* Required during deletion to obtain device flows from logical flows */
manikkaraj kbf256be2019-03-25 00:13:48 +0530113}
114
115func NewFlowManager(dh *DeviceHandler, rsrcMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
116 log.Info("Initializing flow manager")
117 var flowMgr OpenOltFlowMgr
118 flowMgr.deviceHandler = dh
119 flowMgr.resourceMgr = rsrcMgr
120 if err := flowMgr.populateTechProfilePerPonPort(); err != nil {
121 log.Error("Error while populating tech profile mgr\n")
122 return nil
123 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400124 flowMgr.onuIds = make(map[onuIdKey]onuInfo)
125 flowMgr.onuSerialNumbers = make(map[string]onuInfo)
126 flowMgr.onuGemPortIds = make(map[gemPortKey]onuInfo)
127 flowMgr.packetInGemPort = make(map[packetInInfoKey]uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530128 log.Info("Initialization of flow manager success!!")
129 return &flowMgr
130}
131
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400132func (f *OpenOltFlowMgr) generateStoredFlowId(flowId uint32, direction string) (uint64, error) {
133 if direction == UPSTREAM {
134 log.Debug("upstream flow, shifting id")
135 return 0x1<<15 | uint64(flowId), nil
136 } else if direction == DOWNSTREAM {
137 log.Debug("downstream flow, not shifting id")
138 return uint64(flowId), nil
139 } else {
140 log.Debug("Unrecognized direction")
141 return 0, errors.New(fmt.Sprintf("Unrecognized direction %s", direction))
142 }
143}
144
145func (f *OpenOltFlowMgr) registerFlow(flowFromCore *ofp.OfpFlowStats, deviceFlow *openolt_pb2.Flow) {
146 log.Debug("Registering Flow for Device ", log.Fields{"flow": flowFromCore},
147 log.Fields{"device": f.deviceHandler.deviceId})
148
149 var storedFlow ofp.OfpFlowStats
150 storedFlow.Id, _ = f.generateStoredFlowId(deviceFlow.FlowId, deviceFlow.FlowType)
151 log.Debug(fmt.Sprintf("Generated stored device flow. id = %d, flowId = %d, direction = %s", storedFlow.Id,
152 deviceFlow.FlowId, deviceFlow.FlowType))
153 storedFlow.Cookie = flowFromCore.Id
154 f.storedDeviceFlows = append(f.storedDeviceFlows, storedFlow)
155 log.Debugw("updated Stored flow info", log.Fields{"storedDeviceFlows": f.storedDeviceFlows})
156}
157
manikkaraj kbf256be2019-03-25 00:13:48 +0530158func (f *OpenOltFlowMgr) divideAndAddFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
159 var allocId []uint32
160 var gemPorts []uint32
161
162 log.Infow("Dividing flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "portNo": portNo, "classifier": classifierInfo, "action": actionInfo})
163
164 log.Infow("sorting flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "portNo": portNo,
165 "classifierInfo": classifierInfo, "actionInfo": actionInfo})
166
167 uni := getUniPortPath(intfId, onuId, uniId)
168 log.Debugw("Uni port name", log.Fields{"uni": uni})
169 allocId, gemPorts = f.createTcontGemports(intfId, onuId, uniId, uni, portNo, flow.GetTableId())
170 if allocId == nil || gemPorts == nil {
171 log.Error("alloc-id-gem-ports-unavailable")
172 return
173 }
174
175 /* Flows can't be added specific to gemport unless p-bits are received.
176 * Hence adding flows for all gemports
177 */
178 for _, gemPort := range gemPorts {
179 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
180 if ipProto.(uint32) == IP_PROTO_DHCP {
181 log.Info("Adding DHCP flow")
182 f.addDHCPTrapFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
183 } else if ipProto == IP_PROTO_IGMP {
184 log.Info("igmp flow add ignored, not implemented yet")
185 } else {
186 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
187 //return errors.New("Invalid-Classifier-to-handle")
188 }
189 } else if ethType, ok := classifierInfo[ETH_TYPE]; ok {
190 if ethType.(uint32) == EAP_ETH_TYPE {
191 log.Info("Adding EAPOL flow")
192 f.addEAPOLFlow(intfId, onuId, uniId, portNo, flow, allocId[0], gemPort, DEFAULT_MGMT_VLAN)
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400193 if vlan := getSubscriberVlan(utils.GetInPort(flow)); vlan != 0 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530194 f.addEAPOLFlow(intfId, onuId, uniId, portNo, flow, allocId[0], gemPort, vlan)
195 }
196 // Send Techprofile download event to child device in go routine as it takes time
197 go f.sendTPDownloadMsgToChild(intfId, onuId, uniId, uni)
198 }
199 if ethType == LLDP_ETH_TYPE {
200 log.Info("Adding LLDP flow")
201 addLLDPFlow(flow, portNo)
202 }
203 } else if _, ok := actionInfo[PUSH_VLAN]; ok {
204 log.Info("Adding upstream data rule")
205 f.addUpstreamDataFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
206 } else if _, ok := actionInfo[POP_VLAN]; ok {
207 log.Info("Adding Downstream data rule")
208 f.addDownstreamDataFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
209 } else {
210 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
211 }
212 }
213}
214
215// This function allocates tconts and GEM ports for an ONU, currently one TCONT is supported per ONU
216func (f *OpenOltFlowMgr) createTcontGemports(intfId uint32, onuId uint32, uniId uint32, uni string, uniPort uint32, tableID uint32) ([]uint32, []uint32) {
217 var allocID []uint32
218 var gemPortIDs []uint32
219 //If we already have allocated earlier for this onu, render them
Abhilash S.L8ee90712019-04-29 16:24:22 +0530220 if tcontId := f.resourceMgr.GetCurrentAllocIDForOnu(intfId, onuId, uniId); tcontId != 0 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530221 allocID = append(allocID, tcontId)
222 }
223 gemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(intfId, onuId, uniId)
224 if len(allocID) != 0 && len(gemPortIDs) != 0 {
225 log.Debug("Rendered Tcont and GEM ports from resource manager", log.Fields{"intfId": intfId, "onuId": onuId, "uniPort": uniId,
226 "allocID": allocID, "gemPortIDs": gemPortIDs})
227 return allocID, gemPortIDs
228 }
229 log.Debug("Creating New TConts and Gem ports", log.Fields{"pon": intfId, "onu": onuId, "uni": uniId})
230
231 //FIXME: If table id is <= 63 using 64 as table id
232 if tableID < tp.DEFAULT_TECH_PROFILE_TABLE_ID {
233 tableID = tp.DEFAULT_TECH_PROFILE_TABLE_ID
234 }
235 tpPath := f.getTPpath(intfId, uni)
236 // Check tech profile instance already exists for derived port name
237 tech_profile_instance, err := f.techprofile[intfId].GetTPInstanceFromKVStore(tableID, tpPath)
238 if err != nil { // This should not happen, something wrong in KV backend transaction
239 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tableID": tableID, "path": tpPath})
240 return nil, nil
241 }
242 if tech_profile_instance == nil {
243 log.Info("Creating tech profile instance", log.Fields{"path": tpPath})
244 tech_profile_instance = f.techprofile[intfId].CreateTechProfInstance(tableID, uni, intfId)
245 if tech_profile_instance == nil {
246 log.Error("Tech-profile-instance-creation-failed")
247 return nil, nil
248 }
249 } else {
250 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
251 }
252 // Get upstream and downstream scheduler protos
253 us_scheduler := f.techprofile[intfId].GetUsScheduler(tech_profile_instance)
254 ds_scheduler := f.techprofile[intfId].GetDsScheduler(tech_profile_instance)
255 // Get TCONTS protos
256 tconts := f.techprofile[intfId].GetTconts(tech_profile_instance, us_scheduler, ds_scheduler)
257 if len(tconts) == 0 {
258 log.Error("TCONTS not found ")
259 return nil, nil
260 }
261 log.Debugw("Sending Create tcont to device",
262 log.Fields{"onu": onuId, "uni": uniId, "portNo": "", "tconts": tconts})
263 if _, err := f.deviceHandler.Client.CreateTconts(context.Background(),
264 &openolt_pb2.Tconts{IntfId: intfId,
265 OnuId: onuId,
266 UniId: uniId,
267 PortNo: uniPort,
268 Tconts: tconts}); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -0400269 log.Errorw("Error while creating TCONT in device", log.Fields{"error": err})
manikkaraj kbf256be2019-03-25 00:13:48 +0530270 return nil, nil
271 }
272 allocID = append(allocID, tech_profile_instance.UsScheduler.AllocID)
273 for _, gem := range tech_profile_instance.UpstreamGemPortAttributeList {
274 gemPortIDs = append(gemPortIDs, gem.GemportID)
275 }
276 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocID": allocID, "gemports": gemPortIDs})
277 // Send Tconts and GEM ports to KV store
278 f.storeTcontsGEMPortsIntoKVStore(intfId, onuId, uniId, allocID, gemPortIDs)
279 return allocID, gemPortIDs
280}
281
282func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(intfId uint32, onuId uint32, uniId uint32, allocID []uint32, gemPortIDs []uint32) {
283
284 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
285 log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "allocID": allocID, "gemPortIDs": gemPortIDs})
286 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
287 if err := f.resourceMgr.UpdateAllocIdsForOnu(intfId, onuId, uniId, allocID); err != nil {
288 log.Error("Errow while uploading allocID to KV store")
289 }
290 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(intfId, onuId, uniId, gemPortIDs); err != nil {
291 log.Error("Errow while uploading GEMports to KV store")
292 }
293 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(gemPortIDs, intfId, onuId, uniId); err != nil {
294 log.Error("Errow while uploading gemtopon map to KV store")
295 }
296 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400297 for _, gemPort := range gemPortIDs {
298 f.addGemPortToOnuInfoMap(intfId, onuId, gemPort)
299 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530300}
301
302func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
303 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
304 for intfId := range techRange.IntfIds {
305 f.techprofile = append(f.techprofile, f.resourceMgr.ResourceMgrs[uint32(intfId)].TechProfileMgr)
306 }
307 }
308 //Make sure we have as many tech_profiles as there are pon ports on the device
309 if len(f.techprofile) != int(f.resourceMgr.DevInfo.GetPonPorts()) {
310 log.Errorw("Error while populating techprofile",
311 log.Fields{"numofTech": len(f.techprofile), "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
312 return errors.New("Error while populating techprofile mgrs")
313 }
314 log.Infow("Populated techprofile per ponport successfully",
315 log.Fields{"numofTech": len(f.techprofile), "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
316 return nil
317}
318
Manikkaraj k884c1242019-04-11 16:26:42 +0530319func (f *OpenOltFlowMgr) addUpstreamDataFlow(intfId uint32, onuId uint32, uniId uint32,
320 portNo uint32, uplinkClassifier map[string]interface{},
321 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
322 allocId uint32, gemportId uint32) {
323 uplinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
324 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
325 f.addHSIAFlow(intfId, onuId, uniId, portNo, uplinkClassifier, uplinkAction,
326 UPSTREAM, logicalFlow, allocId, gemportId)
327 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530328}
329
Manikkaraj k884c1242019-04-11 16:26:42 +0530330func (f *OpenOltFlowMgr) addDownstreamDataFlow(intfId uint32, onuId uint32, uniId uint32,
331 portNo uint32, downlinkClassifier map[string]interface{},
332 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
333 allocId uint32, gemportId uint32) {
334 downlinkClassifier[PACKET_TAG_TYPE] = DOUBLE_TAG
335 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
336 "downlinkAction": downlinkAction})
manikkaraj k17652a72019-05-06 09:06:36 -0400337 // Ignore private VLAN flow given by decomposer, cannot do anything with this flow
Manikkaraj k884c1242019-04-11 16:26:42 +0530338 if uint32(downlinkClassifier[METADATA].(uint64)) == MkUniPortNum(intfId, onuId, uniId) &&
339 downlinkClassifier[VLAN_VID] == (uint32(ofp.OfpVlanId_OFPVID_PRESENT)|4000) {
340 log.Infow("EAPOL DL flow , Already added ,ignoring it", log.Fields{"downlinkClassifier": downlinkClassifier,
341 "downlinkAction": downlinkAction})
342 return
343 }
344 /* Already this info available classifier? */
345 downlinkAction[POP_VLAN] = true
346 downlinkAction[VLAN_VID] = downlinkClassifier[VLAN_VID]
347 f.addHSIAFlow(intfId, onuId, uniId, portNo, downlinkClassifier, downlinkAction,
348 DOWNSTREAM, logicalFlow, allocId, gemportId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530349}
350
Manikkaraj k884c1242019-04-11 16:26:42 +0530351func (f *OpenOltFlowMgr) addHSIAFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, classifier map[string]interface{},
352 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
353 allocId uint32, gemPortId uint32) {
354 /* One of the OLT platform (Broadcom BAL) requires that symmetric
355 flows require the same flow_id to be used across UL and DL.
356 Since HSIA flow is the only symmetric flow currently, we need to
357 re-use the flow_id across both direction. The 'flow_category'
358 takes priority over flow_cookie to find any available HSIA_FLOW
359 id for the ONU.
360 */
361 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "classifier": classifier,
362 "action": action, "direction": direction, "allocId": allocId, "gemPortId": gemPortId,
363 "logicalFlow": *logicalFlow})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400364 flowCategory := "HSIA"
Manikkaraj k884c1242019-04-11 16:26:42 +0530365 flowStoreCookie := getFlowStoreCookie(classifier, gemPortId)
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400366 flowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, flowCategory)
Manikkaraj k884c1242019-04-11 16:26:42 +0530367 if err != nil {
368 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
369 return
370 }
371 var classifierProto *openolt_pb2.Classifier
372 var actionProto *openolt_pb2.Action
373 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
374 log.Error("Error in making classifier protobuf for hsia flow")
375 return
376 }
377 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
378 if actionProto = makeOpenOltActionField(action); actionProto == nil {
379 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
380 return
381 }
382 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530383 networkIntfId, err := f.getNniIntfID()
384 if err != nil {
385 log.Error("Error in getting NNI interface ID, Failed to add HSIA flow")
386 return
387 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530388 flow := openolt_pb2.Flow{AccessIntfId: int32(intfId),
389 OnuId: int32(onuId),
390 UniId: int32(uniId),
391 FlowId: flowId,
392 FlowType: direction,
393 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530394 NetworkIntfId: int32(networkIntfId),
Manikkaraj k884c1242019-04-11 16:26:42 +0530395 GemportId: int32(gemPortId),
396 Classifier: classifierProto,
397 Action: actionProto,
398 Priority: int32(logicalFlow.Priority),
399 Cookie: logicalFlow.Cookie,
400 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400401 if ok := f.addFlowToDevice(logicalFlow, &flow); ok {
Manikkaraj k884c1242019-04-11 16:26:42 +0530402 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400403 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, "HSIA", flowId)
Manikkaraj k884c1242019-04-11 16:26:42 +0530404 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
405 flow.OnuId,
406 flow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400407 flow.FlowId /*flowCategory,*/, flowsToKVStore); err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530408 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
409 return
410 }
411 }
412}
manikkaraj kbf256be2019-03-25 00:13:48 +0530413func (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 +0530414
415 var dhcpFlow openolt_pb2.Flow
416 var actionProto *openolt_pb2.Action
417 var classifierProto *openolt_pb2.Classifier
418
419 // Clear the action map
420 for k := range action {
421 delete(action, k)
422 }
423
424 action[TRAP_TO_HOST] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400425 classifier[UDP_SRC] = uint32(68)
426 classifier[UDP_DST] = uint32(67)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530427 classifier[PACKET_TAG_TYPE] = SINGLE_TAG
428 delete(classifier, VLAN_VID)
429
430 flowStoreCookie := getFlowStoreCookie(classifier, gemPortId)
431
432 flowID, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
433
434 if err != nil {
435 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
436 return
437 }
438
439 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
440
441 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
442 log.Error("Error in making classifier protobuf for ul flow")
443 return
444 }
445 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
446 if actionProto = makeOpenOltActionField(action); actionProto == nil {
447 log.Error("Error in making action protobuf for ul flow")
448 return
449 }
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530450 networkIntfId, err := f.getNniIntfID()
451 if err != nil {
452 log.Error("Error in getting NNI interface ID, Failed to add DHCP Trap Flow")
453 return
454 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530455
456 dhcpFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
457 OnuId: int32(onuId),
458 UniId: int32(uniId),
459 FlowId: flowID,
460 FlowType: UPSTREAM,
461 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530462 NetworkIntfId: int32(networkIntfId),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530463 GemportId: int32(gemPortId),
464 Classifier: classifierProto,
465 Action: actionProto,
466 Priority: int32(logicalFlow.Priority),
467 Cookie: logicalFlow.Cookie,
468 PortNo: portNo}
469
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400470 if ok := f.addFlowToDevice(logicalFlow, &dhcpFlow); ok {
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530471 log.Debug("DHCP UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400472 flowsToKVStore := f.getUpdatedFlowInfo(&dhcpFlow, flowStoreCookie, "DHCP", flowID)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530473 if err := f.updateFlowInfoToKVStore(dhcpFlow.AccessIntfId,
474 dhcpFlow.OnuId,
475 dhcpFlow.UniId,
476 dhcpFlow.FlowId, flowsToKVStore); err != nil {
477 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
478 return
479 }
480 }
481
manikkaraj kbf256be2019-03-25 00:13:48 +0530482 return
483}
484
485// Add EAPOL to device
486func (f *OpenOltFlowMgr) addEAPOLFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32) {
487 log.Debugw("Adding EAPOL to device", log.Fields{"intfId": intfId, "onuId": onuId, "portNo": portNo, "allocId": allocId, "gemPortId": gemPortId, "vlanId": vlanId, "flow": logicalFlow})
488
489 uplinkClassifier := make(map[string]interface{})
490 uplinkAction := make(map[string]interface{})
491 downlinkClassifier := make(map[string]interface{})
492 downlinkAction := make(map[string]interface{})
493 var upstreamFlow openolt_pb2.Flow
494 var downstreamFlow openolt_pb2.Flow
495
496 // Fill Classfier
497 uplinkClassifier[ETH_TYPE] = uint32(EAP_ETH_TYPE)
498 uplinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
499 uplinkClassifier[VLAN_VID] = vlanId
500 // Fill action
501 uplinkAction[TRAP_TO_HOST] = true
502 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortId)
503 //Add Uplink EAPOL Flow
504 uplinkFlowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
505 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530506 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
507 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530508 }
509 var classifierProto *openolt_pb2.Classifier
510 var actionProto *openolt_pb2.Action
511 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowId})
512
513 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
514 log.Error("Error in making classifier protobuf for ul flow")
515 return
516 }
517 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
518 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
519 log.Error("Error in making action protobuf for ul flow")
520 return
521 }
522 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530523 networkIntfId, err := f.getNniIntfID()
524 if err != nil {
525 log.Error("Error in getting NNI interface ID, Failed to add EAPOL Flow")
526 return
527 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530528 upstreamFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
529 OnuId: int32(onuId),
530 UniId: int32(uniId),
531 FlowId: uplinkFlowId,
532 FlowType: UPSTREAM,
533 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530534 NetworkIntfId: int32(networkIntfId),
manikkaraj kbf256be2019-03-25 00:13:48 +0530535 GemportId: int32(gemPortId),
536 Classifier: classifierProto,
537 Action: actionProto,
538 Priority: int32(logicalFlow.Priority),
539 Cookie: logicalFlow.Cookie,
540 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400541 if ok := f.addFlowToDevice(logicalFlow, &upstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530542 log.Debug("EAPOL UL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400543 flowCategory := "EAPOL"
544 flowsToKVStore := f.getUpdatedFlowInfo(&upstreamFlow, flowStoreCookie, flowCategory, uplinkFlowId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530545 if err := f.updateFlowInfoToKVStore(upstreamFlow.AccessIntfId,
546 upstreamFlow.OnuId,
547 upstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400548 upstreamFlow.FlowId,
549 /* lowCategory, */
550 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530551 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
552 return
553 }
554 }
555
556 if vlanId == DEFAULT_MGMT_VLAN {
557 /* Add Downstream EAPOL Flow, Only for first EAP flow (BAL
558 # requirement)
559 # On one of the platforms (Broadcom BAL), when same DL classifier
560 # vlan was used across multiple ONUs, eapol flow re-adds after
561 # flow delete (cases of onu reboot/disable) fails.
562 # In order to generate unique vlan, a combination of intf_id
563 # onu_id and uniId is used.
564 # uniId defaults to 0, so add 1 to it.
565 */
566 log.Debugw("Creating DL EAPOL flow with default vlan", log.Fields{"vlan": vlanId})
567 specialVlanDlFlow := 4090 - intfId*onuId*(uniId+1)
568 // Assert that we do not generate invalid vlans under no condition
569 if specialVlanDlFlow <= 2 {
570 log.Fatalw("invalid-vlan-generated", log.Fields{"vlan": specialVlanDlFlow})
571 return
572 }
573 log.Debugw("specialVlanEAPOLDlFlow:", log.Fields{"dl_vlan": specialVlanDlFlow})
574 // Fill Classfier
575 downlinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
576 downlinkClassifier[VLAN_VID] = uint32(specialVlanDlFlow)
577 // Fill action
578 downlinkAction[PUSH_VLAN] = true
579 downlinkAction[VLAN_VID] = vlanId
580 flowStoreCookie := getFlowStoreCookie(downlinkClassifier, gemPortId)
581 downlinkFlowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
582 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530583 log.Errorw("flowId unavailable for DL EAPOL",
manikkaraj kbf256be2019-03-25 00:13:48 +0530584 log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
585 return
586 }
587 log.Debugw("Creating DL EAPOL flow",
588 log.Fields{"dl_classifier": downlinkClassifier, "dl_action": downlinkAction, "downlinkFlowId": downlinkFlowId})
589 if classifierProto = makeOpenOltClassifierField(downlinkClassifier); classifierProto == nil {
590 log.Error("Error in making classifier protobuf for downlink flow")
591 return
592 }
593 if actionProto = makeOpenOltActionField(downlinkAction); actionProto == nil {
594 log.Error("Error in making action protobuf for dl flow")
595 return
596 }
597 // Downstream flow in grpc protobuf
598 downstreamFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
599 OnuId: int32(onuId),
600 UniId: int32(uniId),
601 FlowId: downlinkFlowId,
602 FlowType: DOWNSTREAM,
603 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530604 NetworkIntfId: int32(networkIntfId),
manikkaraj kbf256be2019-03-25 00:13:48 +0530605 GemportId: int32(gemPortId),
606 Classifier: classifierProto,
607 Action: actionProto,
608 Priority: int32(logicalFlow.Priority),
609 Cookie: logicalFlow.Cookie,
610 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400611 if ok := f.addFlowToDevice(logicalFlow, &downstreamFlow); ok {
manikkaraj kbf256be2019-03-25 00:13:48 +0530612 log.Debug("EAPOL DL flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400613 flowCategory := ""
614 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamFlow, flowStoreCookie, flowCategory, downlinkFlowId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530615 if err := f.updateFlowInfoToKVStore(downstreamFlow.AccessIntfId,
616 downstreamFlow.OnuId,
617 downstreamFlow.UniId,
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400618 downstreamFlow.FlowId,
619 /* flowCategory, */
620 flowsToKVStore); err != nil {
manikkaraj kbf256be2019-03-25 00:13:48 +0530621 log.Errorw("Error uploading EAPOL DL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
622 return
623 }
624 }
625 } else {
626 log.Infow("EAPOL flow with non-default mgmt vlan is not supported", log.Fields{"vlanId": vlanId})
627 return
628 }
629 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
630}
631
632func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openolt_pb2.Classifier {
633 var classifier openolt_pb2.Classifier
634 if etherType, ok := classifierInfo[ETH_TYPE]; ok {
635 classifier.EthType = etherType.(uint32)
636 }
637 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
638 classifier.IpProto = ipProto.(uint32)
639 }
640 if vlanId, ok := classifierInfo[VLAN_VID]; ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400641 classifier.OVid = (vlanId.(uint32)) & 0xFFF
manikkaraj kbf256be2019-03-25 00:13:48 +0530642 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530643 if metadata, ok := classifierInfo[METADATA]; ok { // TODO: Revisit
644 classifier.IVid = uint32(metadata.(uint64))
manikkaraj kbf256be2019-03-25 00:13:48 +0530645 }
646 if vlanPcp, ok := classifierInfo[VLAN_PCP]; ok {
647 classifier.OPbits = vlanPcp.(uint32)
648 }
649 if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
650 classifier.SrcPort = udpSrc.(uint32)
651 }
652 if udpDst, ok := classifierInfo[UDP_DST]; ok {
653 classifier.DstPort = udpDst.(uint32)
654 }
655 if ipv4Dst, ok := classifierInfo[IPV4_DST]; ok {
656 classifier.DstIp = ipv4Dst.(uint32)
657 }
658 if ipv4Src, ok := classifierInfo[IPV4_SRC]; ok {
659 classifier.SrcIp = ipv4Src.(uint32)
660 }
661 if pktTagType, ok := classifierInfo[PACKET_TAG_TYPE]; ok {
662 if pktTagType.(string) == SINGLE_TAG {
663 classifier.PktTagType = SINGLE_TAG
664 } else if pktTagType.(string) == DOUBLE_TAG {
665 classifier.PktTagType = DOUBLE_TAG
666 } else if pktTagType.(string) == UNTAGGED {
667 classifier.PktTagType = UNTAGGED
668 } else {
669 log.Error("Invalid tag type in classifier") // should not hit
670 return nil
671 }
672 }
673 return &classifier
674}
675
676func makeOpenOltActionField(actionInfo map[string]interface{}) *openolt_pb2.Action {
677 var actionCmd openolt_pb2.ActionCmd
678 var action openolt_pb2.Action
679 action.Cmd = &actionCmd
680 if _, ok := actionInfo[POP_VLAN]; ok {
681 action.OVid = actionInfo[VLAN_VID].(uint32)
682 action.Cmd.RemoveOuterTag = true
683 } else if _, ok := actionInfo[PUSH_VLAN]; ok {
684 action.OVid = actionInfo[VLAN_VID].(uint32)
685 action.Cmd.AddOuterTag = true
686 } else if _, ok := actionInfo[TRAP_TO_HOST]; ok {
687 action.Cmd.TrapToHost = actionInfo[TRAP_TO_HOST].(bool)
688 } else {
689 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
690 return nil
691 }
692 return &action
693}
694
695func (f *OpenOltFlowMgr) getTPpath(intfId uint32, uni string) string {
696 /*
697 FIXME
698 Should get Table id form the flow, as of now hardcoded to DEFAULT_TECH_PROFILE_TABLE_ID (64)
699 'tp_path' contains the suffix part of the tech_profile_instance path. The prefix to the 'tp_path' should be set to
700 TechProfile.KV_STORE_TECH_PROFILE_PATH_PREFIX by the ONU adapter.
701 */
702 return f.techprofile[intfId].GetTechProfileInstanceKVPath(tp.DEFAULT_TECH_PROFILE_TABLE_ID, uni)
703}
704
705func getFlowStoreCookie(classifier map[string]interface{}, gemPortId uint32) uint64 {
706 if len(classifier) == 0 { // should never happen
707 log.Error("Invalid classfier object")
708 return 0
709 }
710 var jsonData []byte
711 var flowString string
712 var err error
713 // TODO: Do we need to marshall ??
714 if jsonData, err = json.Marshal(classifier); err != nil {
715 log.Error("Failed to encode classifier")
716 return 0
717 }
718 flowString = string(jsonData)
719 if gemPortId != 0 {
720 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortId))
721 }
722 h := md5.New()
723 h.Write([]byte(flowString))
724 hash := big.NewInt(0)
725 hash.SetBytes(h.Sum(nil))
726 return hash.Uint64()
727}
728
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400729func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string, deviceFlowId uint32) *[]rsrcMgr.FlowInfo {
manikkaraj k17652a72019-05-06 09:06:36 -0400730 var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400731 var intfId uint32
732 /* For flows which trap out of the NNI, the AccessIntfId is invalid
733 (set to -1). In such cases, we need to refer to the NetworkIntfId .
734 */
735 if flow.AccessIntfId != -1 {
736 intfId = uint32(flow.AccessIntfId)
737 } else {
738 intfId = uint32(flow.NetworkIntfId)
739 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400740 existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -0400741 if existingFlows != nil {
742 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
743 for _, f := range *existingFlows {
744 flows = append(flows, f)
745 }
746 }
747 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 +0530748 return &flows
749}
750
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400751//func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
752// var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
753// var intfId uint32
754// /* For flows which trap out of the NNI, the AccessIntfId is invalid
755// (set to -1). In such cases, we need to refer to the NetworkIntfId .
756// */
757// if flow.AccessIntfId != -1 {
758// intfId = uint32(flow.AccessIntfId)
759// } else {
760// intfId = uint32(flow.NetworkIntfId)
761// }
762// // Get existing flows matching flowid for given subscriber from KV store
763// existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
764// if existingFlows != nil {
765// log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
766// for _, f := range *existingFlows {
767// flows = append(flows, f)
768// }
769// }
770// log.Debugw("Updated flows for given flowID and onuid", log.Fields{"updatedflow": flows, "flowid": flow.FlowId, "onu": flow.OnuId})
771// return &flows
772//}
773
manikkaraj k17652a72019-05-06 09:06:36 -0400774func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(intfId int32, onuId int32, uniId int32, flowId uint32, flows *[]rsrcMgr.FlowInfo) error {
775 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
776 if err := f.resourceMgr.UpdateFlowIDInfo(intfId, onuId, uniId, flowId, flows); err != nil {
777 log.Debug("Error while Storing flow into KV store")
778 return err
779 }
780 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +0530781 return nil
782}
783
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400784func (f *OpenOltFlowMgr) addFlowToDevice(logicalFlow *ofp.OfpFlowStats, deviceFlow *openolt_pb2.Flow) bool {
manikkaraj kbf256be2019-03-25 00:13:48 +0530785 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
786 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
787 if err != nil {
788 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
789 return false
790 }
791 log.Debugw("Flow added to device successfuly ", log.Fields{"flow": *deviceFlow})
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400792 f.registerFlow(logicalFlow, deviceFlow)
793 return true
794}
795
796func (f *OpenOltFlowMgr) removeFlowFromDevice(deviceFlow *openolt_pb2.Flow) bool {
797 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
798 _, err := f.deviceHandler.Client.FlowRemove(context.Background(), deviceFlow)
799 if err != nil {
800 log.Errorw("Failed to Remove flow from device", log.Fields{"err": err, "deviceFlow": deviceFlow})
801 return false
802 }
803 log.Debugw("Flow removed from device successfuly ", log.Fields{"flow": *deviceFlow})
manikkaraj kbf256be2019-03-25 00:13:48 +0530804 return true
805}
806
807/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
808 //update core flows_proxy : flows_proxy.update('/', flows)
809}
810
811func generateStoredId(flowId uint32, direction string)uint32{
812
813 if direction == UPSTREAM{
814 log.Debug("Upstream flow shifting flowid")
815 return ((0x1 << 15) | flowId)
816 }else if direction == DOWNSTREAM{
817 log.Debug("Downstream flow not shifting flowid")
818 return flowId
819 }else{
820 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
821 return flowId
822 }
823}
824
825*/
826
827func addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
828 log.Info("Unimplemented")
829}
830func getUniPortPath(intfId uint32, onuId uint32, uniId uint32) string {
831 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfId, onuId, uniId)
832}
833
Manikkaraj k884c1242019-04-11 16:26:42 +0530834func (f *OpenOltFlowMgr) getOnuChildDevice(intfId uint32, onuId uint32) (*voltha.Device, error) {
835 log.Debugw("GetChildDevice", log.Fields{"pon port": intfId, "onuId": onuId})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400836 parentPortNo := IntfIdToPortNo(intfId, voltha.Port_PON_OLT)
Manikkaraj k884c1242019-04-11 16:26:42 +0530837 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuId)
838 if onuDevice == nil {
839 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuId})
840 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +0530841 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530842 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
843 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530844}
845
846func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
847 log.Info("Unimplemented")
848 return nil
849}
850
851func getSubscriberVlan(inPort uint32) uint32 {
852 /* For EAPOL case we will use default VLAN , so will implement later if required */
853 log.Info("Unimplemented")
854 return 0
855}
856
857func (f *OpenOltFlowMgr) clear_flows_and_scheduler_for_logical_port(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
858 log.Info("Unimplemented")
859}
860
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -0400861func (f *OpenOltFlowMgr) decodeStoredId(id uint64) (uint64, string) {
862 if id>>15 == 0x1 {
863 return id & 0x7fff, UPSTREAM
864 }
865 return id, DOWNSTREAM
866}
867
868func (f *OpenOltFlowMgr) clearFlowFromResourceManager(flow *ofp.OfpFlowStats, flowId uint32, flowDirection string) {
869 log.Debugw("clearFlowFromResourceManager", log.Fields{"flowId": flowId, "flowDirection": flowDirection, "flow": *flow})
870 ponIntf, onuId, uniId, err := FlowExtractInfo(flow, flowDirection)
871 if err != nil {
872 log.Error(err)
873 return
874 }
875 log.Debugw("Extracted access info from flow to be deleted",
876 log.Fields{"ponIntf": ponIntf, "onuId": onuId, "uniId": uniId, "flowId": flowId})
877
878 flowsInfo := f.resourceMgr.GetFlowIDInfo(ponIntf, onuId, uniId, flowId)
879 if flowsInfo == nil {
880 log.Debugw("No FlowInfo found found in KV store",
881 log.Fields{"ponIntf": ponIntf, "onuId": onuId, "uniId": uniId, "flowId": flowId})
882 return
883 }
884 var updatedFlows []rsrcMgr.FlowInfo
885
886 for _, flow := range *flowsInfo {
887 updatedFlows = append(updatedFlows, flow)
888 }
889
890 for i, storedFlow := range updatedFlows {
891 if flowDirection == storedFlow.Flow.FlowType {
892 //Remove the Flow from FlowInfo
893 log.Debugw("Removing flow to be deleted", log.Fields{"flow": storedFlow})
894 updatedFlows = append(updatedFlows[:i], updatedFlows[i+1:]...)
895 break
896 }
897 }
898
899 if len(updatedFlows) >= 0 {
900 // There are still flows referencing the same flow_id.
901 // So the flow should not be freed yet.
902 // For ex: Case of HSIA where same flow is shared
903 // between DS and US.
904 f.updateFlowInfoToKVStore(int32(ponIntf), int32(onuId), int32(uniId), flowId, &updatedFlows)
905 return
906 }
907 log.Debugw("Releasing flow Id to resource manager", log.Fields{"ponIntf": ponIntf, "onuId": onuId, "uniId": uniId, "flowId": flowId})
908 f.resourceMgr.FreeFlowID(ponIntf, onuId, uniId, flowId)
909 flowIds := f.resourceMgr.GetCurrentFlowIDsForOnu(ponIntf, onuId, uniId)
910 if len(flowIds) == 0 {
911 /* TODO: Remove Upstream and Downstream Schedulers */
912 }
913}
914
915func (f *OpenOltFlowMgr) RemoveFlow(flow *ofp.OfpFlowStats) {
916 log.Debugw("Removing Flow", log.Fields{"flow": flow})
917 var deviceFlowsToRemove []ofp.OfpFlowStats
918 var deletedFlowsIdx []int
919 for _, curFlow := range f.storedDeviceFlows {
920 if curFlow.Cookie == flow.Id {
921 log.Debugw("Found found matching flow-cookie", log.Fields{"curFlow": curFlow})
922 deviceFlowsToRemove = append(deviceFlowsToRemove, curFlow)
923 }
924 }
925 log.Debugw("Flows to be deleted", log.Fields{"deviceFlowsToRemove": deviceFlowsToRemove})
926 for index, curFlow := range deviceFlowsToRemove {
927 id, direction := f.decodeStoredId(curFlow.GetId())
928 removeFlowMessage := openolt_pb2.Flow{FlowId: uint32(id), FlowType: direction}
929 if ok := f.removeFlowFromDevice(&removeFlowMessage); ok {
930 log.Debug("Flow removed from device successfully")
931 deletedFlowsIdx = append(deletedFlowsIdx, index)
932 f.clearFlowFromResourceManager(flow, uint32(id), direction) //TODO: Take care of the limitations
933 }
934
935 }
936 // Can be done in separate go routine as it takes time ?
937 for _, flowToRemove := range deletedFlowsIdx {
938 for index, storedFlow := range f.storedDeviceFlows {
939 if deviceFlowsToRemove[flowToRemove].Cookie == storedFlow.Cookie {
940 log.Debugw("Removing flow from local Store", log.Fields{"flow": storedFlow})
941 f.storedDeviceFlows = append(f.storedDeviceFlows[:index], f.storedDeviceFlows[index+1:]...)
942 break
943 }
944 }
945 }
946 log.Debugw("Flows removed from the data store",
947 log.Fields{"number_of_flows_removed": len(deviceFlowsToRemove), "updated_stored_flows": f.storedDeviceFlows})
948 return
949}
950
manikkaraj kbf256be2019-03-25 00:13:48 +0530951func (f *OpenOltFlowMgr) AddFlow(flow *ofp.OfpFlowStats) {
952 classifierInfo := make(map[string]interface{}, 0)
953 actionInfo := make(map[string]interface{}, 0)
954 log.Debug("Adding Flow", log.Fields{"flow": flow})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400955 for _, field := range utils.GetOfbFields(flow) {
956 if field.Type == utils.ETH_TYPE {
manikkaraj kbf256be2019-03-25 00:13:48 +0530957 classifierInfo[ETH_TYPE] = field.GetEthType()
958 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[ETH_TYPE].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400959 } else if field.Type == utils.IP_PROTO {
manikkaraj kbf256be2019-03-25 00:13:48 +0530960 classifierInfo[IP_PROTO] = field.GetIpProto()
961 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IP_PROTO].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400962 } else if field.Type == utils.IN_PORT {
manikkaraj kbf256be2019-03-25 00:13:48 +0530963 classifierInfo[IN_PORT] = field.GetPort()
964 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[IN_PORT].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400965 } else if field.Type == utils.VLAN_VID {
manikkaraj kbf256be2019-03-25 00:13:48 +0530966 classifierInfo[VLAN_VID] = field.GetVlanVid()
967 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VLAN_VID].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400968 } else if field.Type == utils.VLAN_PCP {
manikkaraj kbf256be2019-03-25 00:13:48 +0530969 classifierInfo[VLAN_PCP] = field.GetVlanPcp()
970 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VLAN_PCP].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400971 } else if field.Type == utils.UDP_DST {
manikkaraj kbf256be2019-03-25 00:13:48 +0530972 classifierInfo[UDP_DST] = field.GetUdpDst()
973 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDP_DST].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400974 } else if field.Type == utils.UDP_SRC {
manikkaraj kbf256be2019-03-25 00:13:48 +0530975 classifierInfo[UDP_SRC] = field.GetUdpSrc()
976 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDP_SRC].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400977 } else if field.Type == utils.IPV4_DST {
manikkaraj kbf256be2019-03-25 00:13:48 +0530978 classifierInfo[IPV4_DST] = field.GetIpv4Dst()
979 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[IPV4_DST].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400980 } else if field.Type == utils.IPV4_SRC {
manikkaraj kbf256be2019-03-25 00:13:48 +0530981 classifierInfo[IPV4_SRC] = field.GetIpv4Src()
982 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[IPV4_SRC].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400983 } else if field.Type == utils.METADATA {
manikkaraj kbf256be2019-03-25 00:13:48 +0530984 classifierInfo[METADATA] = field.GetTableMetadata()
985 log.Debug("field-type-metadata", log.Fields{"classifierInfo[METADATA]": classifierInfo[METADATA].(uint64)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400986 } else if field.Type == utils.TUNNEL_ID {
manikkaraj k17652a72019-05-06 09:06:36 -0400987 classifierInfo[TUNNEL_ID] = field.GetTunnelId()
988 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TUNNEL_ID].(uint64)})
manikkaraj kbf256be2019-03-25 00:13:48 +0530989 } else {
990 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
991 return
992 }
993 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400994 for _, action := range utils.GetActions(flow) {
995 if action.Type == utils.OUTPUT {
manikkaraj kbf256be2019-03-25 00:13:48 +0530996 if out := action.GetOutput(); out != nil {
997 actionInfo[OUTPUT] = out.GetPort()
998 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[OUTPUT].(uint32)})
999 } else {
1000 log.Error("Invalid output port in action")
1001 return
1002 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001003 } else if action.Type == utils.POP_VLAN {
manikkaraj kbf256be2019-03-25 00:13:48 +05301004 actionInfo[POP_VLAN] = true
1005 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[IN_PORT].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001006 } else if action.Type == utils.PUSH_VLAN {
manikkaraj kbf256be2019-03-25 00:13:48 +05301007 if out := action.GetPush(); out != nil {
1008 if tpid := out.GetEthertype(); tpid != 0x8100 {
1009 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PUSH_VLAN].(int32)})
1010 } else {
1011 actionInfo[PUSH_VLAN] = true
1012 actionInfo[TPID] = tpid
1013 log.Debugw("action-type-push-vlan",
1014 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[IN_PORT].(uint32)})
1015 }
1016 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001017 } else if action.Type == utils.SET_FIELD {
manikkaraj kbf256be2019-03-25 00:13:48 +05301018 if out := action.GetSetField(); out != nil {
1019 if field := out.GetField(); field != nil {
1020 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
1021 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
1022 return
1023 }
1024 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
1025 if ofbField := field.GetOfbField(); ofbField != nil {
1026 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
1027 if vlan := ofbField.GetVlanVid(); vlan != 0 {
1028 actionInfo[VLAN_VID] = vlan & 0xfff
1029 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VLAN_VID].(uint32)})
1030 } else {
1031 log.Error("No Invalid vlan id in set vlan-vid action")
1032 }
1033 } else {
1034 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
1035 }
1036 }
1037 }
1038 }
1039 } else {
1040 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
1041 return
1042 }
1043 }
manikkaraj k17652a72019-05-06 09:06:36 -04001044 /* Controller bound trap flows */
1045 if isControllerFlow := IsControllerBoundFlow(actionInfo[OUTPUT].(uint32)); isControllerFlow {
1046 log.Debug("Controller bound trap flows, getting inport from tunnelid")
1047 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
1048 if portType := IntfIdToPortTypeName(classifierInfo[IN_PORT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001049 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -04001050 classifierInfo[IN_PORT] = uniPort
1051 log.Debugw("upstream pon-to-controller-flow,inport-in-tunnelid", log.Fields{"newInPort": classifierInfo[IN_PORT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
manikkaraj kbf256be2019-03-25 00:13:48 +05301052 } else {
manikkaraj k17652a72019-05-06 09:06:36 -04001053 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
1054 return
manikkaraj kbf256be2019-03-25 00:13:48 +05301055 }
1056 }
manikkaraj k17652a72019-05-06 09:06:36 -04001057 } else {
1058 log.Debug("Non-Controller flows, getting uniport from tunnelid")
1059 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
1060 if portType := IntfIdToPortTypeName(actionInfo[OUTPUT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001061 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -04001062 actionInfo[OUTPUT] = uniPort
1063 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[OUTPUT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
1064 } else {
1065 log.Debug("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid", log.Fields{"InPort": classifierInfo[IN_PORT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
1066 return
1067 }
1068 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
1069 } else if portType := IntfIdToPortTypeName(classifierInfo[IN_PORT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -04001070 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -04001071 classifierInfo[IN_PORT] = uniPort
1072 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[OUTPUT].(uint32),
1073 "outport": actionInfo[OUTPUT].(uint32)})
1074 } else {
1075 log.Debug("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid", log.Fields{"InPort": classifierInfo[IN_PORT].(uint32),
1076 "outPort": actionInfo[OUTPUT].(uint32)})
1077 return
1078 }
1079 }
1080 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301081 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[IN_PORT], "action_output": actionInfo[OUTPUT]})
1082 portNo, intfId, onuId, uniId := ExtractAccessFromFlow(classifierInfo[IN_PORT].(uint32), actionInfo[OUTPUT].(uint32))
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001083 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
1084 if ipProto.(uint32) == IP_PROTO_DHCP {
1085 if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
1086 if udpSrc.(uint32) == uint32(67) {
1087 log.Debug("trap-dhcp-from-nni-flow")
1088 f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
1089 return
1090 }
1091 }
1092 }
1093 }
manikkaraj kbf256be2019-03-25 00:13:48 +05301094 f.divideAndAddFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow)
1095}
1096
Manikkaraj k884c1242019-04-11 16:26:42 +05301097func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfId uint32, onuId uint32, uniId uint32, uni string) error {
manikkaraj kbf256be2019-03-25 00:13:48 +05301098
Manikkaraj k884c1242019-04-11 16:26:42 +05301099 onuDevice, err := f.getOnuChildDevice(intfId, onuId)
1100 if err != nil {
1101 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuId})
1102 return err
manikkaraj kbf256be2019-03-25 00:13:48 +05301103 }
Manikkaraj k884c1242019-04-11 16:26:42 +05301104 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -04001105
1106 tpPath := f.getTPpath(intfId, uni)
1107 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniId, Path: tpPath}
1108 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
1109 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
1110 tpDownloadMsg,
1111 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
1112 f.deviceHandler.deviceType,
1113 onuDevice.Type,
1114 onuDevice.Id,
1115 onuDevice.ProxyAddress.DeviceId, "")
1116 if sendErr != nil {
1117 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
1118 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
1119 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
1120 return sendErr
1121 }
1122 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +05301123 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +05301124}
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001125
1126// This function adds onu info to cache
1127func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
1128 onu := onuInfo{intfId: intfID, onuId: onuID, serialNumber: serialNum}
1129 onuIDkey := onuIdKey{intfId: intfID, onuId: onuID}
1130 f.onuIds[onuIDkey] = onu
1131 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
1132}
1133
1134// This function stores adds GEMport to ONU map
1135func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfId uint32, onuId uint32, gemPort uint32) {
1136 onuIDkey := onuIdKey{intfId: intfId, onuId: onuId}
1137 if val, ok := f.onuIds[onuIDkey]; ok {
1138 onuInfo := val
1139 gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPort}
1140 f.onuGemPortIds[gemPortKey] = onuInfo
1141 log.Debugw("Cached Gemport to Onuinfo map", log.Fields{"GemPort": gemPort, "intfId": onuInfo.intfId, "onuId": onuInfo.onuId})
1142 return
1143 }
1144 log.Errorw("OnuInfo not found", log.Fields{"intfId": intfId, "onuId": onuId, "gemPort": gemPort})
1145}
1146
1147// This function Lookup maps by serialNumber or (intfId, gemPort)
1148// Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
1149func (f *OpenOltFlowMgr) getOnuIdfromGemPortMap(serialNumber string, intfId uint32, gemPortId uint32) (uint32, error) {
1150 log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPortId": gemPortId})
1151 if serialNumber != "" {
1152 if onuInfo, ok := f.onuSerialNumbers[serialNumber]; ok {
1153 return onuInfo.onuId, nil
1154 }
1155 } else {
1156 gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPortId}
1157 if onuInfo, ok := f.onuGemPortIds[gemPortKey]; ok {
1158 log.Debugw("Retrived onu info from access", log.Fields{"intfId": intfId, "gemPortId": gemPortId, "onuId": onuInfo.onuId})
1159 return onuInfo.onuId, nil
1160 }
1161 }
1162 log.Errorw("ONU ID is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPort": gemPortId})
1163 return uint32(0), errors.New("Key Error ,ONU ID is not found") // ONU ID 0 is not a valid one
1164}
1165
1166// This function computes logical port UNI/NNI port from packet-in indication and returns the same
1167func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openolt_pb2.PacketIndication) (uint32, error) {
1168 var logicalPortNum uint32
1169 var onuId uint32
1170 var err error
1171
1172 if packetIn.IntfType == "pon" {
1173 // packet indication does not have serial number , so sending as nil
1174 if onuId, err = f.getOnuIdfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
1175 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
1176 return logicalPortNum, err
1177 }
1178 if packetIn.PortNo != 0 {
1179 logicalPortNum = packetIn.PortNo
1180 } else {
1181 uniId := uint32(0) // FIXME - multi-uni support
1182 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuId, uniId)
1183 }
1184 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
1185 pktInkey := packetInInfoKey{intfId: packetIn.IntfId, onuId: onuId, logicalPort: logicalPortNum}
1186 f.packetInGemPort[pktInkey] = packetIn.GemportId
1187 } else if packetIn.IntfType == "nni" {
1188 logicalPortNum = IntfIdToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
1189 }
1190 log.Debugw("Retrieved logicalport from packet-in", log.Fields{"logicalPortNum": logicalPortNum, "IntfType": packetIn.IntfType})
1191 return logicalPortNum, nil
1192}
1193
1194func (f *OpenOltFlowMgr) GetPacketOutGemPortId(intfId uint32, onuId uint32, portNum uint32) (uint32, error) {
1195 var gemPortId uint32
1196 var err error
1197 key := packetInInfoKey{intfId: intfId, onuId: onuId, logicalPort: portNum}
1198 if val, ok := f.packetInGemPort[key]; ok {
1199 gemPortId = val
1200 } else {
1201 log.Errorw("Key-Error while fetching packet-out GEM port", log.Fields{"key": key})
1202 err = errors.New("Key-Error while fetching packet-out GEM port")
1203 }
1204 return gemPortId, err
1205}
1206
1207func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
1208 log.Debug("Adding trap-dhcp-of-nni-flow")
1209 action := make(map[string]interface{})
1210 classifier[PACKET_TAG_TYPE] = DOUBLE_TAG
1211 action[TRAP_TO_HOST] = true
1212 /* We manage flowId resource pool on per PON port basis.
1213 Since this situation is tricky, as a hack, we pass the NNI port
1214 index (network_intf_id) as PON port Index for the flowId resource
1215 pool. Also, there is no ONU Id available for trapping DHCP packets
1216 on NNI port, use onu_id as -1 (invalid)
1217 ****************** CAVEAT *******************
1218 This logic works if the NNI Port Id falls within the same valid
1219 range of PON Port Ids. If this doesn't work for some OLT Vendor
1220 we need to have a re-look at this.
1221 *********************************************
1222 */
1223 onuId := -1
1224 uniId := -1
1225 gemPortId := -1
1226 allocId := -1
Devmalya Paul0099c9c2019-06-10 14:40:30 +05301227 networkInterfaceId, err := f.getNniIntfID()
1228 if err != nil {
1229 log.Error("Error in getting NNI interface ID, Failed to add DHCP Trap flow on NNI")
1230 return
1231 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001232 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
1233 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie); present {
1234 log.Debug("Flow-exists--not-re-adding")
1235 return
1236 }
1237 flowId, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie, "")
1238 if err != nil {
1239 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
1240 return
1241 }
1242 var classifierProto *openolt_pb2.Classifier
1243 var actionProto *openolt_pb2.Action
1244 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
1245 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
1246 return
1247 }
1248 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1249 if actionProto = makeOpenOltActionField(action); actionProto == nil {
1250 log.Error("Error in making action protobuf for dhcp trap on nni flow")
1251 return
1252 }
1253 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1254 downstreamflow := openolt_pb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1255 OnuId: int32(onuId), // OnuId not required
1256 UniId: int32(uniId), // UniId not used
1257 FlowId: flowId,
1258 FlowType: DOWNSTREAM,
Devmalya Paul0099c9c2019-06-10 14:40:30 +05301259 AllocId: int32(allocId), // AllocId not used
1260 NetworkIntfId: int32(networkInterfaceId),
1261 GemportId: int32(gemPortId), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001262 Classifier: classifierProto,
1263 Action: actionProto,
1264 Priority: int32(logicalFlow.Priority),
1265 Cookie: logicalFlow.Cookie,
1266 PortNo: portNo}
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001267 if ok := f.addFlowToDevice(logicalFlow, &downstreamflow); ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001268 log.Debug("DHCP trap on NNI flow added to device successfully")
Manjunath Vanarajulu28c3e822019-05-16 11:14:28 -04001269 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "", flowId)
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001270 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceId),
1271 int32(onuId),
1272 int32(uniId),
1273 flowId, flowsToKVStore); err != nil {
1274 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1275 }
1276 }
1277 return
1278}
Devmalya Paul0099c9c2019-06-10 14:40:30 +05301279
1280func (f *OpenOltFlowMgr) getNniIntfID() (int32, error) {
1281 device, err := f.deviceHandler.coreProxy.GetDevice(nil, f.deviceHandler.deviceId, f.deviceHandler.deviceId)
1282 if err != nil {
1283 log.Errorw("Failed to get device", log.Fields{"device-id": f.deviceHandler.deviceId})
1284 return -1, err
1285 }
1286 var portNum uint32
1287 for _, port := range device.Ports {
1288 if port.Type == voltha.Port_ETHERNET_NNI {
1289 portNum = port.PortNo
1290 break
1291 }
1292 }
1293
1294 nniIntfId := IntfIdFromNniPortNum(portNum)
1295 log.Debugw("NNI interface Id", log.Fields{"intf-id": nniIntfId})
1296 return int32(nniIntfId), nil
1297}