blob: 8d9361e58f0d9d452148510795b4917302b5765d [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"
27 fd "github.com/opencord/voltha-go/rw_core/flow_decomposition"
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"
manikkaraj kbf256be2019-03-25 00:13:48 +053034)
35
36const (
37 // Flow categories
38 HSIA_FLOW = "HSIA_FLOW"
39 EAPOL_FLOW = "EAPOL_FLOW"
40
41 IP_PROTO_DHCP = 17
42
43 IP_PROTO_IGMP = 2
44
45 EAP_ETH_TYPE = 0x888e
46 LLDP_ETH_TYPE = 0x88cc
47
48 IGMP_PROTO = 2
49
50 //FIXME - see also BRDCM_DEFAULT_VLAN in broadcom_onu.py
51 DEFAULT_MGMT_VLAN = 4091
52
53 DEFAULT_NETWORK_INTERFACE_ID = 0
54
55 // Openolt Flow
56 UPSTREAM = "upstream"
57 DOWNSTREAM = "downstream"
58 PACKET_TAG_TYPE = "pkt_tag_type"
59 UNTAGGED = "untagged"
60 SINGLE_TAG = "single_tag"
61 DOUBLE_TAG = "double_tag"
62
63 // classifierInfo
manikkaraj k17652a72019-05-06 09:06:36 -040064 ETH_TYPE = "eth_type"
65 TPID = "tpid"
66 IP_PROTO = "ip_proto"
67 IN_PORT = "in_port"
68 VLAN_VID = "vlan_vid"
69 VLAN_PCP = "vlan_pcp"
70 UDP_DST = "udp_dst"
71 UDP_SRC = "udp_src"
72 IPV4_DST = "ipv4_dst"
73 IPV4_SRC = "ipv4_src"
74 METADATA = "metadata"
75 TUNNEL_ID = "tunnel_id"
76 OUTPUT = "output"
manikkaraj kbf256be2019-03-25 00:13:48 +053077 // Action
78 POP_VLAN = "pop_vlan"
79 PUSH_VLAN = "push_vlan"
80 TRAP_TO_HOST = "trap_to_host"
81)
82
manikkaraj k9eb6cac2019-05-09 12:32:03 -040083type onuInfo struct {
84 intfId uint32
85 onuId uint32
86 serialNumber string
87}
88
89type onuIdKey struct {
90 intfId uint32
91 onuId uint32
92}
93
94type gemPortKey struct {
95 intfId uint32
96 gemPort uint32
97}
98
99type packetInInfoKey struct {
100 intfId uint32
101 onuId uint32
102 logicalPort uint32
103}
104
manikkaraj kbf256be2019-03-25 00:13:48 +0530105type OpenOltFlowMgr struct {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400106 techprofile []*tp.TechProfileMgr
107 deviceHandler *DeviceHandler
108 resourceMgr *rsrcMgr.OpenOltResourceMgr
109 onuIds map[onuIdKey]onuInfo //OnuId -> OnuInfo
110 onuSerialNumbers map[string]onuInfo //onu serial_number (string) -> OnuInfo
111 onuGemPortIds map[gemPortKey]onuInfo //GemPortId -> OnuInfo
112 packetInGemPort map[packetInInfoKey]uint32 //packet in gem port
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
132func (f *OpenOltFlowMgr) divideAndAddFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
133 var allocId []uint32
134 var gemPorts []uint32
135
136 log.Infow("Dividing flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "portNo": portNo, "classifier": classifierInfo, "action": actionInfo})
137
138 log.Infow("sorting flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "portNo": portNo,
139 "classifierInfo": classifierInfo, "actionInfo": actionInfo})
140
141 uni := getUniPortPath(intfId, onuId, uniId)
142 log.Debugw("Uni port name", log.Fields{"uni": uni})
143 allocId, gemPorts = f.createTcontGemports(intfId, onuId, uniId, uni, portNo, flow.GetTableId())
144 if allocId == nil || gemPorts == nil {
145 log.Error("alloc-id-gem-ports-unavailable")
146 return
147 }
148
149 /* Flows can't be added specific to gemport unless p-bits are received.
150 * Hence adding flows for all gemports
151 */
152 for _, gemPort := range gemPorts {
153 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
154 if ipProto.(uint32) == IP_PROTO_DHCP {
155 log.Info("Adding DHCP flow")
156 f.addDHCPTrapFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
157 } else if ipProto == IP_PROTO_IGMP {
158 log.Info("igmp flow add ignored, not implemented yet")
159 } else {
160 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
161 //return errors.New("Invalid-Classifier-to-handle")
162 }
163 } else if ethType, ok := classifierInfo[ETH_TYPE]; ok {
164 if ethType.(uint32) == EAP_ETH_TYPE {
165 log.Info("Adding EAPOL flow")
166 f.addEAPOLFlow(intfId, onuId, uniId, portNo, flow, allocId[0], gemPort, DEFAULT_MGMT_VLAN)
167 if vlan := getSubscriberVlan(fd.GetInPort(flow)); vlan != 0 {
168 f.addEAPOLFlow(intfId, onuId, uniId, portNo, flow, allocId[0], gemPort, vlan)
169 }
170 // Send Techprofile download event to child device in go routine as it takes time
171 go f.sendTPDownloadMsgToChild(intfId, onuId, uniId, uni)
172 }
173 if ethType == LLDP_ETH_TYPE {
174 log.Info("Adding LLDP flow")
175 addLLDPFlow(flow, portNo)
176 }
177 } else if _, ok := actionInfo[PUSH_VLAN]; ok {
178 log.Info("Adding upstream data rule")
179 f.addUpstreamDataFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
180 } else if _, ok := actionInfo[POP_VLAN]; ok {
181 log.Info("Adding Downstream data rule")
182 f.addDownstreamDataFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
183 } else {
184 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
185 }
186 }
187}
188
189// This function allocates tconts and GEM ports for an ONU, currently one TCONT is supported per ONU
190func (f *OpenOltFlowMgr) createTcontGemports(intfId uint32, onuId uint32, uniId uint32, uni string, uniPort uint32, tableID uint32) ([]uint32, []uint32) {
191 var allocID []uint32
192 var gemPortIDs []uint32
193 //If we already have allocated earlier for this onu, render them
Abhilash S.L8ee90712019-04-29 16:24:22 +0530194 if tcontId := f.resourceMgr.GetCurrentAllocIDForOnu(intfId, onuId, uniId); tcontId != 0 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530195 allocID = append(allocID, tcontId)
196 }
197 gemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(intfId, onuId, uniId)
198 if len(allocID) != 0 && len(gemPortIDs) != 0 {
199 log.Debug("Rendered Tcont and GEM ports from resource manager", log.Fields{"intfId": intfId, "onuId": onuId, "uniPort": uniId,
200 "allocID": allocID, "gemPortIDs": gemPortIDs})
201 return allocID, gemPortIDs
202 }
203 log.Debug("Creating New TConts and Gem ports", log.Fields{"pon": intfId, "onu": onuId, "uni": uniId})
204
205 //FIXME: If table id is <= 63 using 64 as table id
206 if tableID < tp.DEFAULT_TECH_PROFILE_TABLE_ID {
207 tableID = tp.DEFAULT_TECH_PROFILE_TABLE_ID
208 }
209 tpPath := f.getTPpath(intfId, uni)
210 // Check tech profile instance already exists for derived port name
211 tech_profile_instance, err := f.techprofile[intfId].GetTPInstanceFromKVStore(tableID, tpPath)
212 if err != nil { // This should not happen, something wrong in KV backend transaction
213 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tableID": tableID, "path": tpPath})
214 return nil, nil
215 }
216 if tech_profile_instance == nil {
217 log.Info("Creating tech profile instance", log.Fields{"path": tpPath})
218 tech_profile_instance = f.techprofile[intfId].CreateTechProfInstance(tableID, uni, intfId)
219 if tech_profile_instance == nil {
220 log.Error("Tech-profile-instance-creation-failed")
221 return nil, nil
222 }
223 } else {
224 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
225 }
226 // Get upstream and downstream scheduler protos
227 us_scheduler := f.techprofile[intfId].GetUsScheduler(tech_profile_instance)
228 ds_scheduler := f.techprofile[intfId].GetDsScheduler(tech_profile_instance)
229 // Get TCONTS protos
230 tconts := f.techprofile[intfId].GetTconts(tech_profile_instance, us_scheduler, ds_scheduler)
231 if len(tconts) == 0 {
232 log.Error("TCONTS not found ")
233 return nil, nil
234 }
235 log.Debugw("Sending Create tcont to device",
236 log.Fields{"onu": onuId, "uni": uniId, "portNo": "", "tconts": tconts})
237 if _, err := f.deviceHandler.Client.CreateTconts(context.Background(),
238 &openolt_pb2.Tconts{IntfId: intfId,
239 OnuId: onuId,
240 UniId: uniId,
241 PortNo: uniPort,
242 Tconts: tconts}); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -0400243 log.Errorw("Error while creating TCONT in device", log.Fields{"error": err})
manikkaraj kbf256be2019-03-25 00:13:48 +0530244 return nil, nil
245 }
246 allocID = append(allocID, tech_profile_instance.UsScheduler.AllocID)
247 for _, gem := range tech_profile_instance.UpstreamGemPortAttributeList {
248 gemPortIDs = append(gemPortIDs, gem.GemportID)
249 }
250 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocID": allocID, "gemports": gemPortIDs})
251 // Send Tconts and GEM ports to KV store
252 f.storeTcontsGEMPortsIntoKVStore(intfId, onuId, uniId, allocID, gemPortIDs)
253 return allocID, gemPortIDs
254}
255
256func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(intfId uint32, onuId uint32, uniId uint32, allocID []uint32, gemPortIDs []uint32) {
257
258 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
259 log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "allocID": allocID, "gemPortIDs": gemPortIDs})
260 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
261 if err := f.resourceMgr.UpdateAllocIdsForOnu(intfId, onuId, uniId, allocID); err != nil {
262 log.Error("Errow while uploading allocID to KV store")
263 }
264 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(intfId, onuId, uniId, gemPortIDs); err != nil {
265 log.Error("Errow while uploading GEMports to KV store")
266 }
267 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(gemPortIDs, intfId, onuId, uniId); err != nil {
268 log.Error("Errow while uploading gemtopon map to KV store")
269 }
270 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400271 for _, gemPort := range gemPortIDs {
272 f.addGemPortToOnuInfoMap(intfId, onuId, gemPort)
273 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530274}
275
276func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
277 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
278 for intfId := range techRange.IntfIds {
279 f.techprofile = append(f.techprofile, f.resourceMgr.ResourceMgrs[uint32(intfId)].TechProfileMgr)
280 }
281 }
282 //Make sure we have as many tech_profiles as there are pon ports on the device
283 if len(f.techprofile) != int(f.resourceMgr.DevInfo.GetPonPorts()) {
284 log.Errorw("Error while populating techprofile",
285 log.Fields{"numofTech": len(f.techprofile), "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
286 return errors.New("Error while populating techprofile mgrs")
287 }
288 log.Infow("Populated techprofile per ponport successfully",
289 log.Fields{"numofTech": len(f.techprofile), "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
290 return nil
291}
292
Manikkaraj k884c1242019-04-11 16:26:42 +0530293func (f *OpenOltFlowMgr) addUpstreamDataFlow(intfId uint32, onuId uint32, uniId uint32,
294 portNo uint32, uplinkClassifier map[string]interface{},
295 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
296 allocId uint32, gemportId uint32) {
297 uplinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
298 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
299 f.addHSIAFlow(intfId, onuId, uniId, portNo, uplinkClassifier, uplinkAction,
300 UPSTREAM, logicalFlow, allocId, gemportId)
301 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530302}
303
Manikkaraj k884c1242019-04-11 16:26:42 +0530304func (f *OpenOltFlowMgr) addDownstreamDataFlow(intfId uint32, onuId uint32, uniId uint32,
305 portNo uint32, downlinkClassifier map[string]interface{},
306 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
307 allocId uint32, gemportId uint32) {
308 downlinkClassifier[PACKET_TAG_TYPE] = DOUBLE_TAG
309 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
310 "downlinkAction": downlinkAction})
manikkaraj k17652a72019-05-06 09:06:36 -0400311 // Ignore private VLAN flow given by decomposer, cannot do anything with this flow
Manikkaraj k884c1242019-04-11 16:26:42 +0530312 if uint32(downlinkClassifier[METADATA].(uint64)) == MkUniPortNum(intfId, onuId, uniId) &&
313 downlinkClassifier[VLAN_VID] == (uint32(ofp.OfpVlanId_OFPVID_PRESENT)|4000) {
314 log.Infow("EAPOL DL flow , Already added ,ignoring it", log.Fields{"downlinkClassifier": downlinkClassifier,
315 "downlinkAction": downlinkAction})
316 return
317 }
318 /* Already this info available classifier? */
319 downlinkAction[POP_VLAN] = true
320 downlinkAction[VLAN_VID] = downlinkClassifier[VLAN_VID]
321 f.addHSIAFlow(intfId, onuId, uniId, portNo, downlinkClassifier, downlinkAction,
322 DOWNSTREAM, logicalFlow, allocId, gemportId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530323}
324
Manikkaraj k884c1242019-04-11 16:26:42 +0530325func (f *OpenOltFlowMgr) addHSIAFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, classifier map[string]interface{},
326 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
327 allocId uint32, gemPortId uint32) {
328 /* One of the OLT platform (Broadcom BAL) requires that symmetric
329 flows require the same flow_id to be used across UL and DL.
330 Since HSIA flow is the only symmetric flow currently, we need to
331 re-use the flow_id across both direction. The 'flow_category'
332 takes priority over flow_cookie to find any available HSIA_FLOW
333 id for the ONU.
334 */
335 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "classifier": classifier,
336 "action": action, "direction": direction, "allocId": allocId, "gemPortId": gemPortId,
337 "logicalFlow": *logicalFlow})
338 flowStoreCookie := getFlowStoreCookie(classifier, gemPortId)
339 flowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "HSIA")
340 if err != nil {
341 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
342 return
343 }
344 var classifierProto *openolt_pb2.Classifier
345 var actionProto *openolt_pb2.Action
346 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
347 log.Error("Error in making classifier protobuf for hsia flow")
348 return
349 }
350 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
351 if actionProto = makeOpenOltActionField(action); actionProto == nil {
352 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
353 return
354 }
355 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
356 flow := openolt_pb2.Flow{AccessIntfId: int32(intfId),
357 OnuId: int32(onuId),
358 UniId: int32(uniId),
359 FlowId: flowId,
360 FlowType: direction,
361 AllocId: int32(allocId),
362 NetworkIntfId: DEFAULT_NETWORK_INTERFACE_ID, // one NNI port is supported now
363 GemportId: int32(gemPortId),
364 Classifier: classifierProto,
365 Action: actionProto,
366 Priority: int32(logicalFlow.Priority),
367 Cookie: logicalFlow.Cookie,
368 PortNo: portNo}
369 if ok := f.addFlowToDevice(&flow); ok {
370 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
371 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, "HSIA")
372 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
373 flow.OnuId,
374 flow.UniId,
375 flow.FlowId, flowsToKVStore); err != nil {
376 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
377 return
378 }
379 }
380}
manikkaraj kbf256be2019-03-25 00:13:48 +0530381func (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 +0530382
383 var dhcpFlow openolt_pb2.Flow
384 var actionProto *openolt_pb2.Action
385 var classifierProto *openolt_pb2.Classifier
386
387 // Clear the action map
388 for k := range action {
389 delete(action, k)
390 }
391
392 action[TRAP_TO_HOST] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400393 classifier[UDP_SRC] = uint32(68)
394 classifier[UDP_DST] = uint32(67)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530395 classifier[PACKET_TAG_TYPE] = SINGLE_TAG
396 delete(classifier, VLAN_VID)
397
398 flowStoreCookie := getFlowStoreCookie(classifier, gemPortId)
399
400 flowID, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
401
402 if err != nil {
403 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
404 return
405 }
406
407 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
408
409 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
410 log.Error("Error in making classifier protobuf for ul flow")
411 return
412 }
413 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
414 if actionProto = makeOpenOltActionField(action); actionProto == nil {
415 log.Error("Error in making action protobuf for ul flow")
416 return
417 }
418
419 dhcpFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
420 OnuId: int32(onuId),
421 UniId: int32(uniId),
422 FlowId: flowID,
423 FlowType: UPSTREAM,
424 AllocId: int32(allocId),
425 NetworkIntfId: DEFAULT_NETWORK_INTERFACE_ID, // one NNI port is supported now
426 GemportId: int32(gemPortId),
427 Classifier: classifierProto,
428 Action: actionProto,
429 Priority: int32(logicalFlow.Priority),
430 Cookie: logicalFlow.Cookie,
431 PortNo: portNo}
432
433 if ok := f.addFlowToDevice(&dhcpFlow); ok {
434 log.Debug("DHCP UL flow added to device successfully")
435 flowsToKVStore := f.getUpdatedFlowInfo(&dhcpFlow, flowStoreCookie, "DHCP")
436 if err := f.updateFlowInfoToKVStore(dhcpFlow.AccessIntfId,
437 dhcpFlow.OnuId,
438 dhcpFlow.UniId,
439 dhcpFlow.FlowId, flowsToKVStore); err != nil {
440 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
441 return
442 }
443 }
444
manikkaraj kbf256be2019-03-25 00:13:48 +0530445 return
446}
447
448// Add EAPOL to device
449func (f *OpenOltFlowMgr) addEAPOLFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32) {
450 log.Debugw("Adding EAPOL to device", log.Fields{"intfId": intfId, "onuId": onuId, "portNo": portNo, "allocId": allocId, "gemPortId": gemPortId, "vlanId": vlanId, "flow": logicalFlow})
451
452 uplinkClassifier := make(map[string]interface{})
453 uplinkAction := make(map[string]interface{})
454 downlinkClassifier := make(map[string]interface{})
455 downlinkAction := make(map[string]interface{})
456 var upstreamFlow openolt_pb2.Flow
457 var downstreamFlow openolt_pb2.Flow
458
459 // Fill Classfier
460 uplinkClassifier[ETH_TYPE] = uint32(EAP_ETH_TYPE)
461 uplinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
462 uplinkClassifier[VLAN_VID] = vlanId
463 // Fill action
464 uplinkAction[TRAP_TO_HOST] = true
465 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortId)
466 //Add Uplink EAPOL Flow
467 uplinkFlowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
468 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530469 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
470 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530471 }
472 var classifierProto *openolt_pb2.Classifier
473 var actionProto *openolt_pb2.Action
474 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowId})
475
476 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
477 log.Error("Error in making classifier protobuf for ul flow")
478 return
479 }
480 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
481 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
482 log.Error("Error in making action protobuf for ul flow")
483 return
484 }
485 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
486 upstreamFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
487 OnuId: int32(onuId),
488 UniId: int32(uniId),
489 FlowId: uplinkFlowId,
490 FlowType: UPSTREAM,
491 AllocId: int32(allocId),
492 NetworkIntfId: DEFAULT_NETWORK_INTERFACE_ID, // one NNI port is supported now
493 GemportId: int32(gemPortId),
494 Classifier: classifierProto,
495 Action: actionProto,
496 Priority: int32(logicalFlow.Priority),
497 Cookie: logicalFlow.Cookie,
498 PortNo: portNo}
499 if ok := f.addFlowToDevice(&upstreamFlow); ok {
500 log.Debug("EAPOL UL flow added to device successfully")
501 flowsToKVStore := f.getUpdatedFlowInfo(&upstreamFlow, flowStoreCookie, "EAPOL")
502 if err := f.updateFlowInfoToKVStore(upstreamFlow.AccessIntfId,
503 upstreamFlow.OnuId,
504 upstreamFlow.UniId,
505 upstreamFlow.FlowId, flowsToKVStore); err != nil {
506 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
507 return
508 }
509 }
510
511 if vlanId == DEFAULT_MGMT_VLAN {
512 /* Add Downstream EAPOL Flow, Only for first EAP flow (BAL
513 # requirement)
514 # On one of the platforms (Broadcom BAL), when same DL classifier
515 # vlan was used across multiple ONUs, eapol flow re-adds after
516 # flow delete (cases of onu reboot/disable) fails.
517 # In order to generate unique vlan, a combination of intf_id
518 # onu_id and uniId is used.
519 # uniId defaults to 0, so add 1 to it.
520 */
521 log.Debugw("Creating DL EAPOL flow with default vlan", log.Fields{"vlan": vlanId})
522 specialVlanDlFlow := 4090 - intfId*onuId*(uniId+1)
523 // Assert that we do not generate invalid vlans under no condition
524 if specialVlanDlFlow <= 2 {
525 log.Fatalw("invalid-vlan-generated", log.Fields{"vlan": specialVlanDlFlow})
526 return
527 }
528 log.Debugw("specialVlanEAPOLDlFlow:", log.Fields{"dl_vlan": specialVlanDlFlow})
529 // Fill Classfier
530 downlinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
531 downlinkClassifier[VLAN_VID] = uint32(specialVlanDlFlow)
532 // Fill action
533 downlinkAction[PUSH_VLAN] = true
534 downlinkAction[VLAN_VID] = vlanId
535 flowStoreCookie := getFlowStoreCookie(downlinkClassifier, gemPortId)
536 downlinkFlowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
537 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530538 log.Errorw("flowId unavailable for DL EAPOL",
manikkaraj kbf256be2019-03-25 00:13:48 +0530539 log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
540 return
541 }
542 log.Debugw("Creating DL EAPOL flow",
543 log.Fields{"dl_classifier": downlinkClassifier, "dl_action": downlinkAction, "downlinkFlowId": downlinkFlowId})
544 if classifierProto = makeOpenOltClassifierField(downlinkClassifier); classifierProto == nil {
545 log.Error("Error in making classifier protobuf for downlink flow")
546 return
547 }
548 if actionProto = makeOpenOltActionField(downlinkAction); actionProto == nil {
549 log.Error("Error in making action protobuf for dl flow")
550 return
551 }
552 // Downstream flow in grpc protobuf
553 downstreamFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
554 OnuId: int32(onuId),
555 UniId: int32(uniId),
556 FlowId: downlinkFlowId,
557 FlowType: DOWNSTREAM,
558 AllocId: int32(allocId),
559 NetworkIntfId: DEFAULT_NETWORK_INTERFACE_ID,
560 GemportId: int32(gemPortId),
561 Classifier: classifierProto,
562 Action: actionProto,
563 Priority: int32(logicalFlow.Priority),
564 Cookie: logicalFlow.Cookie,
565 PortNo: portNo}
566 if ok := f.addFlowToDevice(&downstreamFlow); ok {
567 log.Debug("EAPOL DL flow added to device successfully")
568 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamFlow, flowStoreCookie, "")
569 if err := f.updateFlowInfoToKVStore(downstreamFlow.AccessIntfId,
570 downstreamFlow.OnuId,
571 downstreamFlow.UniId,
572 downstreamFlow.FlowId, flowsToKVStore); err != nil {
573 log.Errorw("Error uploading EAPOL DL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
574 return
575 }
576 }
577 } else {
578 log.Infow("EAPOL flow with non-default mgmt vlan is not supported", log.Fields{"vlanId": vlanId})
579 return
580 }
581 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
582}
583
584func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openolt_pb2.Classifier {
585 var classifier openolt_pb2.Classifier
586 if etherType, ok := classifierInfo[ETH_TYPE]; ok {
587 classifier.EthType = etherType.(uint32)
588 }
589 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
590 classifier.IpProto = ipProto.(uint32)
591 }
592 if vlanId, ok := classifierInfo[VLAN_VID]; ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400593 classifier.OVid = (vlanId.(uint32)) & 0xFFF
manikkaraj kbf256be2019-03-25 00:13:48 +0530594 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530595 if metadata, ok := classifierInfo[METADATA]; ok { // TODO: Revisit
596 classifier.IVid = uint32(metadata.(uint64))
manikkaraj kbf256be2019-03-25 00:13:48 +0530597 }
598 if vlanPcp, ok := classifierInfo[VLAN_PCP]; ok {
599 classifier.OPbits = vlanPcp.(uint32)
600 }
601 if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
602 classifier.SrcPort = udpSrc.(uint32)
603 }
604 if udpDst, ok := classifierInfo[UDP_DST]; ok {
605 classifier.DstPort = udpDst.(uint32)
606 }
607 if ipv4Dst, ok := classifierInfo[IPV4_DST]; ok {
608 classifier.DstIp = ipv4Dst.(uint32)
609 }
610 if ipv4Src, ok := classifierInfo[IPV4_SRC]; ok {
611 classifier.SrcIp = ipv4Src.(uint32)
612 }
613 if pktTagType, ok := classifierInfo[PACKET_TAG_TYPE]; ok {
614 if pktTagType.(string) == SINGLE_TAG {
615 classifier.PktTagType = SINGLE_TAG
616 } else if pktTagType.(string) == DOUBLE_TAG {
617 classifier.PktTagType = DOUBLE_TAG
618 } else if pktTagType.(string) == UNTAGGED {
619 classifier.PktTagType = UNTAGGED
620 } else {
621 log.Error("Invalid tag type in classifier") // should not hit
622 return nil
623 }
624 }
625 return &classifier
626}
627
628func makeOpenOltActionField(actionInfo map[string]interface{}) *openolt_pb2.Action {
629 var actionCmd openolt_pb2.ActionCmd
630 var action openolt_pb2.Action
631 action.Cmd = &actionCmd
632 if _, ok := actionInfo[POP_VLAN]; ok {
633 action.OVid = actionInfo[VLAN_VID].(uint32)
634 action.Cmd.RemoveOuterTag = true
635 } else if _, ok := actionInfo[PUSH_VLAN]; ok {
636 action.OVid = actionInfo[VLAN_VID].(uint32)
637 action.Cmd.AddOuterTag = true
638 } else if _, ok := actionInfo[TRAP_TO_HOST]; ok {
639 action.Cmd.TrapToHost = actionInfo[TRAP_TO_HOST].(bool)
640 } else {
641 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
642 return nil
643 }
644 return &action
645}
646
647func (f *OpenOltFlowMgr) getTPpath(intfId uint32, uni string) string {
648 /*
649 FIXME
650 Should get Table id form the flow, as of now hardcoded to DEFAULT_TECH_PROFILE_TABLE_ID (64)
651 'tp_path' contains the suffix part of the tech_profile_instance path. The prefix to the 'tp_path' should be set to
652 TechProfile.KV_STORE_TECH_PROFILE_PATH_PREFIX by the ONU adapter.
653 */
654 return f.techprofile[intfId].GetTechProfileInstanceKVPath(tp.DEFAULT_TECH_PROFILE_TABLE_ID, uni)
655}
656
657func getFlowStoreCookie(classifier map[string]interface{}, gemPortId uint32) uint64 {
658 if len(classifier) == 0 { // should never happen
659 log.Error("Invalid classfier object")
660 return 0
661 }
662 var jsonData []byte
663 var flowString string
664 var err error
665 // TODO: Do we need to marshall ??
666 if jsonData, err = json.Marshal(classifier); err != nil {
667 log.Error("Failed to encode classifier")
668 return 0
669 }
670 flowString = string(jsonData)
671 if gemPortId != 0 {
672 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortId))
673 }
674 h := md5.New()
675 h.Write([]byte(flowString))
676 hash := big.NewInt(0)
677 hash.SetBytes(h.Sum(nil))
678 return hash.Uint64()
679}
680
manikkaraj k17652a72019-05-06 09:06:36 -0400681func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
682 var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400683 var intfId uint32
684 /* For flows which trap out of the NNI, the AccessIntfId is invalid
685 (set to -1). In such cases, we need to refer to the NetworkIntfId .
686 */
687 if flow.AccessIntfId != -1 {
688 intfId = uint32(flow.AccessIntfId)
689 } else {
690 intfId = uint32(flow.NetworkIntfId)
691 }
692 // Get existing flows matching flowid for given subscriber from KV store
693 existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -0400694 if existingFlows != nil {
695 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
696 for _, f := range *existingFlows {
697 flows = append(flows, f)
698 }
699 }
700 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 +0530701 return &flows
702}
703
manikkaraj k17652a72019-05-06 09:06:36 -0400704func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(intfId int32, onuId int32, uniId int32, flowId uint32, flows *[]rsrcMgr.FlowInfo) error {
705 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
706 if err := f.resourceMgr.UpdateFlowIDInfo(intfId, onuId, uniId, flowId, flows); err != nil {
707 log.Debug("Error while Storing flow into KV store")
708 return err
709 }
710 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +0530711 return nil
712}
713
714func (f *OpenOltFlowMgr) addFlowToDevice(deviceFlow *openolt_pb2.Flow) bool {
715 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
716 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
717 if err != nil {
718 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
719 return false
720 }
721 log.Debugw("Flow added to device successfuly ", log.Fields{"flow": *deviceFlow})
722 return true
723}
724
725/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
726 //update core flows_proxy : flows_proxy.update('/', flows)
727}
728
729func generateStoredId(flowId uint32, direction string)uint32{
730
731 if direction == UPSTREAM{
732 log.Debug("Upstream flow shifting flowid")
733 return ((0x1 << 15) | flowId)
734 }else if direction == DOWNSTREAM{
735 log.Debug("Downstream flow not shifting flowid")
736 return flowId
737 }else{
738 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
739 return flowId
740 }
741}
742
743*/
744
745func addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
746 log.Info("Unimplemented")
747}
748func getUniPortPath(intfId uint32, onuId uint32, uniId uint32) string {
749 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfId, onuId, uniId)
750}
751
Manikkaraj k884c1242019-04-11 16:26:42 +0530752func (f *OpenOltFlowMgr) getOnuChildDevice(intfId uint32, onuId uint32) (*voltha.Device, error) {
753 log.Debugw("GetChildDevice", log.Fields{"pon port": intfId, "onuId": onuId})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400754 parentPortNo := IntfIdToPortNo(intfId, voltha.Port_PON_OLT)
Manikkaraj k884c1242019-04-11 16:26:42 +0530755 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuId)
756 if onuDevice == nil {
757 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuId})
758 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +0530759 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530760 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
761 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530762}
763
764func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
765 log.Info("Unimplemented")
766 return nil
767}
768
769func getSubscriberVlan(inPort uint32) uint32 {
770 /* For EAPOL case we will use default VLAN , so will implement later if required */
771 log.Info("Unimplemented")
772 return 0
773}
774
775func (f *OpenOltFlowMgr) clear_flows_and_scheduler_for_logical_port(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
776 log.Info("Unimplemented")
777}
778
779func (f *OpenOltFlowMgr) AddFlow(flow *ofp.OfpFlowStats) {
780 classifierInfo := make(map[string]interface{}, 0)
781 actionInfo := make(map[string]interface{}, 0)
782 log.Debug("Adding Flow", log.Fields{"flow": flow})
783 for _, field := range fd.GetOfbFields(flow) {
784 if field.Type == fd.ETH_TYPE {
785 classifierInfo[ETH_TYPE] = field.GetEthType()
786 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[ETH_TYPE].(uint32)})
787 } else if field.Type == fd.IP_PROTO {
788 classifierInfo[IP_PROTO] = field.GetIpProto()
789 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IP_PROTO].(uint32)})
790 } else if field.Type == fd.IN_PORT {
791 classifierInfo[IN_PORT] = field.GetPort()
792 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[IN_PORT].(uint32)})
793 } else if field.Type == fd.VLAN_VID {
794 classifierInfo[VLAN_VID] = field.GetVlanVid()
795 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VLAN_VID].(uint32)})
796 } else if field.Type == fd.VLAN_PCP {
797 classifierInfo[VLAN_PCP] = field.GetVlanPcp()
798 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VLAN_PCP].(uint32)})
799 } else if field.Type == fd.UDP_DST {
800 classifierInfo[UDP_DST] = field.GetUdpDst()
801 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDP_DST].(uint32)})
802 } else if field.Type == fd.UDP_SRC {
803 classifierInfo[UDP_SRC] = field.GetUdpSrc()
804 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDP_SRC].(uint32)})
805 } else if field.Type == fd.IPV4_DST {
806 classifierInfo[IPV4_DST] = field.GetIpv4Dst()
807 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[IPV4_DST].(uint32)})
808 } else if field.Type == fd.IPV4_SRC {
809 classifierInfo[IPV4_SRC] = field.GetIpv4Src()
810 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[IPV4_SRC].(uint32)})
811 } else if field.Type == fd.METADATA {
812 classifierInfo[METADATA] = field.GetTableMetadata()
813 log.Debug("field-type-metadata", log.Fields{"classifierInfo[METADATA]": classifierInfo[METADATA].(uint64)})
manikkaraj k17652a72019-05-06 09:06:36 -0400814 } else if field.Type == fd.TUNNEL_ID {
815 classifierInfo[TUNNEL_ID] = field.GetTunnelId()
816 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TUNNEL_ID].(uint64)})
manikkaraj kbf256be2019-03-25 00:13:48 +0530817 } else {
818 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
819 return
820 }
821 }
822 for _, action := range fd.GetActions(flow) {
823 if action.Type == fd.OUTPUT {
824 if out := action.GetOutput(); out != nil {
825 actionInfo[OUTPUT] = out.GetPort()
826 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[OUTPUT].(uint32)})
827 } else {
828 log.Error("Invalid output port in action")
829 return
830 }
831 } else if action.Type == fd.POP_VLAN {
manikkaraj kbf256be2019-03-25 00:13:48 +0530832 actionInfo[POP_VLAN] = true
833 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[IN_PORT].(uint32)})
834 } else if action.Type == fd.PUSH_VLAN {
835 if out := action.GetPush(); out != nil {
836 if tpid := out.GetEthertype(); tpid != 0x8100 {
837 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PUSH_VLAN].(int32)})
838 } else {
839 actionInfo[PUSH_VLAN] = true
840 actionInfo[TPID] = tpid
841 log.Debugw("action-type-push-vlan",
842 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[IN_PORT].(uint32)})
843 }
844 }
845 } else if action.Type == fd.SET_FIELD {
846 if out := action.GetSetField(); out != nil {
847 if field := out.GetField(); field != nil {
848 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
849 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
850 return
851 }
852 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
853 if ofbField := field.GetOfbField(); ofbField != nil {
854 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
855 if vlan := ofbField.GetVlanVid(); vlan != 0 {
856 actionInfo[VLAN_VID] = vlan & 0xfff
857 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VLAN_VID].(uint32)})
858 } else {
859 log.Error("No Invalid vlan id in set vlan-vid action")
860 }
861 } else {
862 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
863 }
864 }
865 }
866 }
867 } else {
868 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
869 return
870 }
871 }
manikkaraj k17652a72019-05-06 09:06:36 -0400872 /* Controller bound trap flows */
873 if isControllerFlow := IsControllerBoundFlow(actionInfo[OUTPUT].(uint32)); isControllerFlow {
874 log.Debug("Controller bound trap flows, getting inport from tunnelid")
875 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
876 if portType := IntfIdToPortTypeName(classifierInfo[IN_PORT].(uint32)); portType == voltha.Port_PON_OLT {
877 if uniPort := fd.GetChildPortFromTunnelId(flow); uniPort != 0 {
878 classifierInfo[IN_PORT] = uniPort
879 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 +0530880 } else {
manikkaraj k17652a72019-05-06 09:06:36 -0400881 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
882 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530883 }
884 }
manikkaraj k17652a72019-05-06 09:06:36 -0400885 } else {
886 log.Debug("Non-Controller flows, getting uniport from tunnelid")
887 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
888 if portType := IntfIdToPortTypeName(actionInfo[OUTPUT].(uint32)); portType == voltha.Port_PON_OLT {
889 if uniPort := fd.GetChildPortFromTunnelId(flow); uniPort != 0 {
890 actionInfo[OUTPUT] = uniPort
891 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[OUTPUT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
892 } else {
893 log.Debug("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid", log.Fields{"InPort": classifierInfo[IN_PORT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
894 return
895 }
896 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
897 } else if portType := IntfIdToPortTypeName(classifierInfo[IN_PORT].(uint32)); portType == voltha.Port_PON_OLT {
898 if uniPort := fd.GetChildPortFromTunnelId(flow); uniPort != 0 {
899 classifierInfo[IN_PORT] = uniPort
900 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[OUTPUT].(uint32),
901 "outport": actionInfo[OUTPUT].(uint32)})
902 } else {
903 log.Debug("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid", log.Fields{"InPort": classifierInfo[IN_PORT].(uint32),
904 "outPort": actionInfo[OUTPUT].(uint32)})
905 return
906 }
907 }
908 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530909 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[IN_PORT], "action_output": actionInfo[OUTPUT]})
910 portNo, intfId, onuId, uniId := ExtractAccessFromFlow(classifierInfo[IN_PORT].(uint32), actionInfo[OUTPUT].(uint32))
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400911 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
912 if ipProto.(uint32) == IP_PROTO_DHCP {
913 if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
914 if udpSrc.(uint32) == uint32(67) {
915 log.Debug("trap-dhcp-from-nni-flow")
916 f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
917 return
918 }
919 }
920 }
921 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530922 f.divideAndAddFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow)
923}
924
Manikkaraj k884c1242019-04-11 16:26:42 +0530925func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfId uint32, onuId uint32, uniId uint32, uni string) error {
manikkaraj kbf256be2019-03-25 00:13:48 +0530926
Manikkaraj k884c1242019-04-11 16:26:42 +0530927 onuDevice, err := f.getOnuChildDevice(intfId, onuId)
928 if err != nil {
929 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuId})
930 return err
manikkaraj kbf256be2019-03-25 00:13:48 +0530931 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530932 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -0400933
934 tpPath := f.getTPpath(intfId, uni)
935 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniId, Path: tpPath}
936 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
937 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
938 tpDownloadMsg,
939 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
940 f.deviceHandler.deviceType,
941 onuDevice.Type,
942 onuDevice.Id,
943 onuDevice.ProxyAddress.DeviceId, "")
944 if sendErr != nil {
945 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
946 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
947 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
948 return sendErr
949 }
950 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +0530951 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530952}
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400953
954// This function adds onu info to cache
955func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
956 onu := onuInfo{intfId: intfID, onuId: onuID, serialNumber: serialNum}
957 onuIDkey := onuIdKey{intfId: intfID, onuId: onuID}
958 f.onuIds[onuIDkey] = onu
959 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
960}
961
962// This function stores adds GEMport to ONU map
963func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfId uint32, onuId uint32, gemPort uint32) {
964 onuIDkey := onuIdKey{intfId: intfId, onuId: onuId}
965 if val, ok := f.onuIds[onuIDkey]; ok {
966 onuInfo := val
967 gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPort}
968 f.onuGemPortIds[gemPortKey] = onuInfo
969 log.Debugw("Cached Gemport to Onuinfo map", log.Fields{"GemPort": gemPort, "intfId": onuInfo.intfId, "onuId": onuInfo.onuId})
970 return
971 }
972 log.Errorw("OnuInfo not found", log.Fields{"intfId": intfId, "onuId": onuId, "gemPort": gemPort})
973}
974
975// This function Lookup maps by serialNumber or (intfId, gemPort)
976// Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
977func (f *OpenOltFlowMgr) getOnuIdfromGemPortMap(serialNumber string, intfId uint32, gemPortId uint32) (uint32, error) {
978 log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPortId": gemPortId})
979 if serialNumber != "" {
980 if onuInfo, ok := f.onuSerialNumbers[serialNumber]; ok {
981 return onuInfo.onuId, nil
982 }
983 } else {
984 gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPortId}
985 if onuInfo, ok := f.onuGemPortIds[gemPortKey]; ok {
986 log.Debugw("Retrived onu info from access", log.Fields{"intfId": intfId, "gemPortId": gemPortId, "onuId": onuInfo.onuId})
987 return onuInfo.onuId, nil
988 }
989 }
990 log.Errorw("ONU ID is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPort": gemPortId})
991 return uint32(0), errors.New("Key Error ,ONU ID is not found") // ONU ID 0 is not a valid one
992}
993
994// This function computes logical port UNI/NNI port from packet-in indication and returns the same
995func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openolt_pb2.PacketIndication) (uint32, error) {
996 var logicalPortNum uint32
997 var onuId uint32
998 var err error
999
1000 if packetIn.IntfType == "pon" {
1001 // packet indication does not have serial number , so sending as nil
1002 if onuId, err = f.getOnuIdfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
1003 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
1004 return logicalPortNum, err
1005 }
1006 if packetIn.PortNo != 0 {
1007 logicalPortNum = packetIn.PortNo
1008 } else {
1009 uniId := uint32(0) // FIXME - multi-uni support
1010 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuId, uniId)
1011 }
1012 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
1013 pktInkey := packetInInfoKey{intfId: packetIn.IntfId, onuId: onuId, logicalPort: logicalPortNum}
1014 f.packetInGemPort[pktInkey] = packetIn.GemportId
1015 } else if packetIn.IntfType == "nni" {
1016 logicalPortNum = IntfIdToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
1017 }
1018 log.Debugw("Retrieved logicalport from packet-in", log.Fields{"logicalPortNum": logicalPortNum, "IntfType": packetIn.IntfType})
1019 return logicalPortNum, nil
1020}
1021
1022func (f *OpenOltFlowMgr) GetPacketOutGemPortId(intfId uint32, onuId uint32, portNum uint32) (uint32, error) {
1023 var gemPortId uint32
1024 var err error
1025 key := packetInInfoKey{intfId: intfId, onuId: onuId, logicalPort: portNum}
1026 if val, ok := f.packetInGemPort[key]; ok {
1027 gemPortId = val
1028 } else {
1029 log.Errorw("Key-Error while fetching packet-out GEM port", log.Fields{"key": key})
1030 err = errors.New("Key-Error while fetching packet-out GEM port")
1031 }
1032 return gemPortId, err
1033}
1034
1035func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
1036 log.Debug("Adding trap-dhcp-of-nni-flow")
1037 action := make(map[string]interface{})
1038 classifier[PACKET_TAG_TYPE] = DOUBLE_TAG
1039 action[TRAP_TO_HOST] = true
1040 /* We manage flowId resource pool on per PON port basis.
1041 Since this situation is tricky, as a hack, we pass the NNI port
1042 index (network_intf_id) as PON port Index for the flowId resource
1043 pool. Also, there is no ONU Id available for trapping DHCP packets
1044 on NNI port, use onu_id as -1 (invalid)
1045 ****************** CAVEAT *******************
1046 This logic works if the NNI Port Id falls within the same valid
1047 range of PON Port Ids. If this doesn't work for some OLT Vendor
1048 we need to have a re-look at this.
1049 *********************************************
1050 */
1051 onuId := -1
1052 uniId := -1
1053 gemPortId := -1
1054 allocId := -1
1055 networkInterfaceId := DEFAULT_NETWORK_INTERFACE_ID
1056 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
1057 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie); present {
1058 log.Debug("Flow-exists--not-re-adding")
1059 return
1060 }
1061 flowId, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie, "")
1062 if err != nil {
1063 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
1064 return
1065 }
1066 var classifierProto *openolt_pb2.Classifier
1067 var actionProto *openolt_pb2.Action
1068 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
1069 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
1070 return
1071 }
1072 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1073 if actionProto = makeOpenOltActionField(action); actionProto == nil {
1074 log.Error("Error in making action protobuf for dhcp trap on nni flow")
1075 return
1076 }
1077 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1078 downstreamflow := openolt_pb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1079 OnuId: int32(onuId), // OnuId not required
1080 UniId: int32(uniId), // UniId not used
1081 FlowId: flowId,
1082 FlowType: DOWNSTREAM,
1083 AllocId: int32(allocId), // AllocId not used
1084 NetworkIntfId: DEFAULT_NETWORK_INTERFACE_ID, // one NNI port is supported now
1085 GemportId: int32(gemPortId), // GemportId not used
1086 Classifier: classifierProto,
1087 Action: actionProto,
1088 Priority: int32(logicalFlow.Priority),
1089 Cookie: logicalFlow.Cookie,
1090 PortNo: portNo}
1091 if ok := f.addFlowToDevice(&downstreamflow); ok {
1092 log.Debug("DHCP trap on NNI flow added to device successfully")
1093 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "")
1094 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceId),
1095 int32(onuId),
1096 int32(uniId),
1097 flowId, flowsToKVStore); err != nil {
1098 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1099 }
1100 }
1101 return
1102}