blob: 7ccf97da28e2f81923530055410ce2f854554f48 [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"
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
manikkaraj kbf256be2019-03-25 00:13:48 +053053 // Openolt Flow
54 UPSTREAM = "upstream"
55 DOWNSTREAM = "downstream"
56 PACKET_TAG_TYPE = "pkt_tag_type"
57 UNTAGGED = "untagged"
58 SINGLE_TAG = "single_tag"
59 DOUBLE_TAG = "double_tag"
60
61 // classifierInfo
manikkaraj k17652a72019-05-06 09:06:36 -040062 ETH_TYPE = "eth_type"
63 TPID = "tpid"
64 IP_PROTO = "ip_proto"
65 IN_PORT = "in_port"
66 VLAN_VID = "vlan_vid"
67 VLAN_PCP = "vlan_pcp"
68 UDP_DST = "udp_dst"
69 UDP_SRC = "udp_src"
70 IPV4_DST = "ipv4_dst"
71 IPV4_SRC = "ipv4_src"
72 METADATA = "metadata"
73 TUNNEL_ID = "tunnel_id"
74 OUTPUT = "output"
manikkaraj kbf256be2019-03-25 00:13:48 +053075 // Action
76 POP_VLAN = "pop_vlan"
77 PUSH_VLAN = "push_vlan"
78 TRAP_TO_HOST = "trap_to_host"
79)
80
manikkaraj k9eb6cac2019-05-09 12:32:03 -040081type onuInfo struct {
82 intfId uint32
83 onuId uint32
84 serialNumber string
85}
86
87type onuIdKey struct {
88 intfId uint32
89 onuId uint32
90}
91
92type gemPortKey struct {
93 intfId uint32
94 gemPort uint32
95}
96
97type packetInInfoKey struct {
98 intfId uint32
99 onuId uint32
100 logicalPort uint32
101}
102
manikkaraj kbf256be2019-03-25 00:13:48 +0530103type OpenOltFlowMgr struct {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400104 techprofile []*tp.TechProfileMgr
105 deviceHandler *DeviceHandler
106 resourceMgr *rsrcMgr.OpenOltResourceMgr
107 onuIds map[onuIdKey]onuInfo //OnuId -> OnuInfo
108 onuSerialNumbers map[string]onuInfo //onu serial_number (string) -> OnuInfo
109 onuGemPortIds map[gemPortKey]onuInfo //GemPortId -> OnuInfo
110 packetInGemPort map[packetInInfoKey]uint32 //packet in gem port
manikkaraj kbf256be2019-03-25 00:13:48 +0530111}
112
113func NewFlowManager(dh *DeviceHandler, rsrcMgr *rsrcMgr.OpenOltResourceMgr) *OpenOltFlowMgr {
114 log.Info("Initializing flow manager")
115 var flowMgr OpenOltFlowMgr
116 flowMgr.deviceHandler = dh
117 flowMgr.resourceMgr = rsrcMgr
118 if err := flowMgr.populateTechProfilePerPonPort(); err != nil {
119 log.Error("Error while populating tech profile mgr\n")
120 return nil
121 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400122 flowMgr.onuIds = make(map[onuIdKey]onuInfo)
123 flowMgr.onuSerialNumbers = make(map[string]onuInfo)
124 flowMgr.onuGemPortIds = make(map[gemPortKey]onuInfo)
125 flowMgr.packetInGemPort = make(map[packetInInfoKey]uint32)
manikkaraj kbf256be2019-03-25 00:13:48 +0530126 log.Info("Initialization of flow manager success!!")
127 return &flowMgr
128}
129
130func (f *OpenOltFlowMgr) divideAndAddFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, classifierInfo map[string]interface{}, actionInfo map[string]interface{}, flow *ofp.OfpFlowStats) {
131 var allocId []uint32
132 var gemPorts []uint32
133
134 log.Infow("Dividing flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "portNo": portNo, "classifier": classifierInfo, "action": actionInfo})
135
136 log.Infow("sorting flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "portNo": portNo,
137 "classifierInfo": classifierInfo, "actionInfo": actionInfo})
138
139 uni := getUniPortPath(intfId, onuId, uniId)
140 log.Debugw("Uni port name", log.Fields{"uni": uni})
141 allocId, gemPorts = f.createTcontGemports(intfId, onuId, uniId, uni, portNo, flow.GetTableId())
142 if allocId == nil || gemPorts == nil {
143 log.Error("alloc-id-gem-ports-unavailable")
144 return
145 }
146
147 /* Flows can't be added specific to gemport unless p-bits are received.
148 * Hence adding flows for all gemports
149 */
150 for _, gemPort := range gemPorts {
151 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
152 if ipProto.(uint32) == IP_PROTO_DHCP {
153 log.Info("Adding DHCP flow")
154 f.addDHCPTrapFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
155 } else if ipProto == IP_PROTO_IGMP {
156 log.Info("igmp flow add ignored, not implemented yet")
157 } else {
158 log.Errorw("Invalid-Classifier-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo})
159 //return errors.New("Invalid-Classifier-to-handle")
160 }
161 } else if ethType, ok := classifierInfo[ETH_TYPE]; ok {
162 if ethType.(uint32) == EAP_ETH_TYPE {
163 log.Info("Adding EAPOL flow")
164 f.addEAPOLFlow(intfId, onuId, uniId, portNo, flow, allocId[0], gemPort, DEFAULT_MGMT_VLAN)
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400165 if vlan := getSubscriberVlan(utils.GetInPort(flow)); vlan != 0 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530166 f.addEAPOLFlow(intfId, onuId, uniId, portNo, flow, allocId[0], gemPort, vlan)
167 }
168 // Send Techprofile download event to child device in go routine as it takes time
169 go f.sendTPDownloadMsgToChild(intfId, onuId, uniId, uni)
170 }
171 if ethType == LLDP_ETH_TYPE {
172 log.Info("Adding LLDP flow")
173 addLLDPFlow(flow, portNo)
174 }
175 } else if _, ok := actionInfo[PUSH_VLAN]; ok {
176 log.Info("Adding upstream data rule")
177 f.addUpstreamDataFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
178 } else if _, ok := actionInfo[POP_VLAN]; ok {
179 log.Info("Adding Downstream data rule")
180 f.addDownstreamDataFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow, allocId[0], gemPort)
181 } else {
182 log.Errorw("Invalid-flow-type-to-handle", log.Fields{"classifier": classifierInfo, "action": actionInfo, "flow": flow})
183 }
184 }
185}
186
187// This function allocates tconts and GEM ports for an ONU, currently one TCONT is supported per ONU
188func (f *OpenOltFlowMgr) createTcontGemports(intfId uint32, onuId uint32, uniId uint32, uni string, uniPort uint32, tableID uint32) ([]uint32, []uint32) {
189 var allocID []uint32
190 var gemPortIDs []uint32
191 //If we already have allocated earlier for this onu, render them
Abhilash S.L8ee90712019-04-29 16:24:22 +0530192 if tcontId := f.resourceMgr.GetCurrentAllocIDForOnu(intfId, onuId, uniId); tcontId != 0 {
manikkaraj kbf256be2019-03-25 00:13:48 +0530193 allocID = append(allocID, tcontId)
194 }
195 gemPortIDs = f.resourceMgr.GetCurrentGEMPortIDsForOnu(intfId, onuId, uniId)
196 if len(allocID) != 0 && len(gemPortIDs) != 0 {
197 log.Debug("Rendered Tcont and GEM ports from resource manager", log.Fields{"intfId": intfId, "onuId": onuId, "uniPort": uniId,
198 "allocID": allocID, "gemPortIDs": gemPortIDs})
199 return allocID, gemPortIDs
200 }
201 log.Debug("Creating New TConts and Gem ports", log.Fields{"pon": intfId, "onu": onuId, "uni": uniId})
202
203 //FIXME: If table id is <= 63 using 64 as table id
204 if tableID < tp.DEFAULT_TECH_PROFILE_TABLE_ID {
205 tableID = tp.DEFAULT_TECH_PROFILE_TABLE_ID
206 }
207 tpPath := f.getTPpath(intfId, uni)
208 // Check tech profile instance already exists for derived port name
209 tech_profile_instance, err := f.techprofile[intfId].GetTPInstanceFromKVStore(tableID, tpPath)
210 if err != nil { // This should not happen, something wrong in KV backend transaction
211 log.Errorw("Error in fetching tech profile instance from KV store", log.Fields{"tableID": tableID, "path": tpPath})
212 return nil, nil
213 }
214 if tech_profile_instance == nil {
215 log.Info("Creating tech profile instance", log.Fields{"path": tpPath})
216 tech_profile_instance = f.techprofile[intfId].CreateTechProfInstance(tableID, uni, intfId)
217 if tech_profile_instance == nil {
218 log.Error("Tech-profile-instance-creation-failed")
219 return nil, nil
220 }
221 } else {
222 log.Debugw("Tech-profile-instance-already-exist-for-given port-name", log.Fields{"uni": uni})
223 }
224 // Get upstream and downstream scheduler protos
225 us_scheduler := f.techprofile[intfId].GetUsScheduler(tech_profile_instance)
226 ds_scheduler := f.techprofile[intfId].GetDsScheduler(tech_profile_instance)
227 // Get TCONTS protos
228 tconts := f.techprofile[intfId].GetTconts(tech_profile_instance, us_scheduler, ds_scheduler)
229 if len(tconts) == 0 {
230 log.Error("TCONTS not found ")
231 return nil, nil
232 }
233 log.Debugw("Sending Create tcont to device",
234 log.Fields{"onu": onuId, "uni": uniId, "portNo": "", "tconts": tconts})
235 if _, err := f.deviceHandler.Client.CreateTconts(context.Background(),
236 &openolt_pb2.Tconts{IntfId: intfId,
237 OnuId: onuId,
238 UniId: uniId,
239 PortNo: uniPort,
240 Tconts: tconts}); err != nil {
manikkaraj k17652a72019-05-06 09:06:36 -0400241 log.Errorw("Error while creating TCONT in device", log.Fields{"error": err})
manikkaraj kbf256be2019-03-25 00:13:48 +0530242 return nil, nil
243 }
244 allocID = append(allocID, tech_profile_instance.UsScheduler.AllocID)
245 for _, gem := range tech_profile_instance.UpstreamGemPortAttributeList {
246 gemPortIDs = append(gemPortIDs, gem.GemportID)
247 }
248 log.Debugw("Allocated Tcont and GEM ports", log.Fields{"allocID": allocID, "gemports": gemPortIDs})
249 // Send Tconts and GEM ports to KV store
250 f.storeTcontsGEMPortsIntoKVStore(intfId, onuId, uniId, allocID, gemPortIDs)
251 return allocID, gemPortIDs
252}
253
254func (f *OpenOltFlowMgr) storeTcontsGEMPortsIntoKVStore(intfId uint32, onuId uint32, uniId uint32, allocID []uint32, gemPortIDs []uint32) {
255
256 log.Debugw("Storing allocated Tconts and GEM ports into KV store",
257 log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "allocID": allocID, "gemPortIDs": gemPortIDs})
258 /* Update the allocated alloc_id and gem_port_id for the ONU/UNI to KV store */
259 if err := f.resourceMgr.UpdateAllocIdsForOnu(intfId, onuId, uniId, allocID); err != nil {
260 log.Error("Errow while uploading allocID to KV store")
261 }
262 if err := f.resourceMgr.UpdateGEMPortIDsForOnu(intfId, onuId, uniId, gemPortIDs); err != nil {
263 log.Error("Errow while uploading GEMports to KV store")
264 }
265 if err := f.resourceMgr.UpdateGEMportsPonportToOnuMapOnKVStore(gemPortIDs, intfId, onuId, uniId); err != nil {
266 log.Error("Errow while uploading gemtopon map to KV store")
267 }
268 log.Debug("Stored tconts and GEM into KV store successfully")
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400269 for _, gemPort := range gemPortIDs {
270 f.addGemPortToOnuInfoMap(intfId, onuId, gemPort)
271 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530272}
273
274func (f *OpenOltFlowMgr) populateTechProfilePerPonPort() error {
275 for _, techRange := range f.resourceMgr.DevInfo.Ranges {
276 for intfId := range techRange.IntfIds {
277 f.techprofile = append(f.techprofile, f.resourceMgr.ResourceMgrs[uint32(intfId)].TechProfileMgr)
278 }
279 }
280 //Make sure we have as many tech_profiles as there are pon ports on the device
281 if len(f.techprofile) != int(f.resourceMgr.DevInfo.GetPonPorts()) {
282 log.Errorw("Error while populating techprofile",
283 log.Fields{"numofTech": len(f.techprofile), "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
284 return errors.New("Error while populating techprofile mgrs")
285 }
286 log.Infow("Populated techprofile per ponport successfully",
287 log.Fields{"numofTech": len(f.techprofile), "numPonPorts": f.resourceMgr.DevInfo.GetPonPorts()})
288 return nil
289}
290
Manikkaraj k884c1242019-04-11 16:26:42 +0530291func (f *OpenOltFlowMgr) addUpstreamDataFlow(intfId uint32, onuId uint32, uniId uint32,
292 portNo uint32, uplinkClassifier map[string]interface{},
293 uplinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
294 allocId uint32, gemportId uint32) {
295 uplinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
296 log.Debugw("Adding upstream data flow", log.Fields{"uplinkClassifier": uplinkClassifier, "uplinkAction": uplinkAction})
297 f.addHSIAFlow(intfId, onuId, uniId, portNo, uplinkClassifier, uplinkAction,
298 UPSTREAM, logicalFlow, allocId, gemportId)
299 /* TODO: Install Secondary EAP on the subscriber vlan */
manikkaraj kbf256be2019-03-25 00:13:48 +0530300}
301
Manikkaraj k884c1242019-04-11 16:26:42 +0530302func (f *OpenOltFlowMgr) addDownstreamDataFlow(intfId uint32, onuId uint32, uniId uint32,
303 portNo uint32, downlinkClassifier map[string]interface{},
304 downlinkAction map[string]interface{}, logicalFlow *ofp.OfpFlowStats,
305 allocId uint32, gemportId uint32) {
306 downlinkClassifier[PACKET_TAG_TYPE] = DOUBLE_TAG
307 log.Debugw("Adding downstream data flow", log.Fields{"downlinkClassifier": downlinkClassifier,
308 "downlinkAction": downlinkAction})
manikkaraj k17652a72019-05-06 09:06:36 -0400309 // Ignore private VLAN flow given by decomposer, cannot do anything with this flow
Manikkaraj k884c1242019-04-11 16:26:42 +0530310 if uint32(downlinkClassifier[METADATA].(uint64)) == MkUniPortNum(intfId, onuId, uniId) &&
311 downlinkClassifier[VLAN_VID] == (uint32(ofp.OfpVlanId_OFPVID_PRESENT)|4000) {
312 log.Infow("EAPOL DL flow , Already added ,ignoring it", log.Fields{"downlinkClassifier": downlinkClassifier,
313 "downlinkAction": downlinkAction})
314 return
315 }
316 /* Already this info available classifier? */
317 downlinkAction[POP_VLAN] = true
318 downlinkAction[VLAN_VID] = downlinkClassifier[VLAN_VID]
319 f.addHSIAFlow(intfId, onuId, uniId, portNo, downlinkClassifier, downlinkAction,
320 DOWNSTREAM, logicalFlow, allocId, gemportId)
manikkaraj kbf256be2019-03-25 00:13:48 +0530321}
322
Manikkaraj k884c1242019-04-11 16:26:42 +0530323func (f *OpenOltFlowMgr) addHSIAFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, classifier map[string]interface{},
324 action map[string]interface{}, direction string, logicalFlow *ofp.OfpFlowStats,
325 allocId uint32, gemPortId uint32) {
326 /* One of the OLT platform (Broadcom BAL) requires that symmetric
327 flows require the same flow_id to be used across UL and DL.
328 Since HSIA flow is the only symmetric flow currently, we need to
329 re-use the flow_id across both direction. The 'flow_category'
330 takes priority over flow_cookie to find any available HSIA_FLOW
331 id for the ONU.
332 */
333 log.Debugw("Adding HSIA flow", log.Fields{"intfId": intfId, "onuId": onuId, "uniId": uniId, "classifier": classifier,
334 "action": action, "direction": direction, "allocId": allocId, "gemPortId": gemPortId,
335 "logicalFlow": *logicalFlow})
336 flowStoreCookie := getFlowStoreCookie(classifier, gemPortId)
337 flowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "HSIA")
338 if err != nil {
339 log.Errorw("Flow id unavailable for HSIA flow", log.Fields{"direction": direction})
340 return
341 }
342 var classifierProto *openolt_pb2.Classifier
343 var actionProto *openolt_pb2.Action
344 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
345 log.Error("Error in making classifier protobuf for hsia flow")
346 return
347 }
348 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
349 if actionProto = makeOpenOltActionField(action); actionProto == nil {
350 log.Errorw("Error in making action protobuf for hsia flow", log.Fields{"direction": direction})
351 return
352 }
353 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530354 networkIntfId, err := f.getNniIntfID()
355 if err != nil {
356 log.Error("Error in getting NNI interface ID, Failed to add HSIA flow")
357 return
358 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530359 flow := openolt_pb2.Flow{AccessIntfId: int32(intfId),
360 OnuId: int32(onuId),
361 UniId: int32(uniId),
362 FlowId: flowId,
363 FlowType: direction,
364 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530365 NetworkIntfId: int32(networkIntfId),
Manikkaraj k884c1242019-04-11 16:26:42 +0530366 GemportId: int32(gemPortId),
367 Classifier: classifierProto,
368 Action: actionProto,
369 Priority: int32(logicalFlow.Priority),
370 Cookie: logicalFlow.Cookie,
371 PortNo: portNo}
372 if ok := f.addFlowToDevice(&flow); ok {
373 log.Debug("HSIA flow added to device successfully", log.Fields{"direction": direction})
374 flowsToKVStore := f.getUpdatedFlowInfo(&flow, flowStoreCookie, "HSIA")
375 if err := f.updateFlowInfoToKVStore(flow.AccessIntfId,
376 flow.OnuId,
377 flow.UniId,
378 flow.FlowId, flowsToKVStore); err != nil {
379 log.Errorw("Error uploading HSIA flow into KV store", log.Fields{"flow": flow, "direction": direction, "error": err})
380 return
381 }
382 }
383}
manikkaraj kbf256be2019-03-25 00:13:48 +0530384func (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 +0530385
386 var dhcpFlow openolt_pb2.Flow
387 var actionProto *openolt_pb2.Action
388 var classifierProto *openolt_pb2.Classifier
389
390 // Clear the action map
391 for k := range action {
392 delete(action, k)
393 }
394
395 action[TRAP_TO_HOST] = true
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400396 classifier[UDP_SRC] = uint32(68)
397 classifier[UDP_DST] = uint32(67)
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530398 classifier[PACKET_TAG_TYPE] = SINGLE_TAG
399 delete(classifier, VLAN_VID)
400
401 flowStoreCookie := getFlowStoreCookie(classifier, gemPortId)
402
403 flowID, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
404
405 if err != nil {
406 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
407 return
408 }
409
410 log.Debugw("Creating UL DHCP flow", log.Fields{"ul_classifier": classifier, "ul_action": action, "uplinkFlowId": flowID})
411
412 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
413 log.Error("Error in making classifier protobuf for ul flow")
414 return
415 }
416 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
417 if actionProto = makeOpenOltActionField(action); actionProto == nil {
418 log.Error("Error in making action protobuf for ul flow")
419 return
420 }
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530421 networkIntfId, err := f.getNniIntfID()
422 if err != nil {
423 log.Error("Error in getting NNI interface ID, Failed to add DHCP Trap Flow")
424 return
425 }
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530426
427 dhcpFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
428 OnuId: int32(onuId),
429 UniId: int32(uniId),
430 FlowId: flowID,
431 FlowType: UPSTREAM,
432 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530433 NetworkIntfId: int32(networkIntfId),
Manjunath Vanarajuluadc57d12019-04-23 11:07:21 +0530434 GemportId: int32(gemPortId),
435 Classifier: classifierProto,
436 Action: actionProto,
437 Priority: int32(logicalFlow.Priority),
438 Cookie: logicalFlow.Cookie,
439 PortNo: portNo}
440
441 if ok := f.addFlowToDevice(&dhcpFlow); ok {
442 log.Debug("DHCP UL flow added to device successfully")
443 flowsToKVStore := f.getUpdatedFlowInfo(&dhcpFlow, flowStoreCookie, "DHCP")
444 if err := f.updateFlowInfoToKVStore(dhcpFlow.AccessIntfId,
445 dhcpFlow.OnuId,
446 dhcpFlow.UniId,
447 dhcpFlow.FlowId, flowsToKVStore); err != nil {
448 log.Errorw("Error uploading DHCP UL flow into KV store", log.Fields{"flow": dhcpFlow, "error": err})
449 return
450 }
451 }
452
manikkaraj kbf256be2019-03-25 00:13:48 +0530453 return
454}
455
456// Add EAPOL to device
457func (f *OpenOltFlowMgr) addEAPOLFlow(intfId uint32, onuId uint32, uniId uint32, portNo uint32, logicalFlow *ofp.OfpFlowStats, allocId uint32, gemPortId uint32, vlanId uint32) {
458 log.Debugw("Adding EAPOL to device", log.Fields{"intfId": intfId, "onuId": onuId, "portNo": portNo, "allocId": allocId, "gemPortId": gemPortId, "vlanId": vlanId, "flow": logicalFlow})
459
460 uplinkClassifier := make(map[string]interface{})
461 uplinkAction := make(map[string]interface{})
462 downlinkClassifier := make(map[string]interface{})
463 downlinkAction := make(map[string]interface{})
464 var upstreamFlow openolt_pb2.Flow
465 var downstreamFlow openolt_pb2.Flow
466
467 // Fill Classfier
468 uplinkClassifier[ETH_TYPE] = uint32(EAP_ETH_TYPE)
469 uplinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
470 uplinkClassifier[VLAN_VID] = vlanId
471 // Fill action
472 uplinkAction[TRAP_TO_HOST] = true
473 flowStoreCookie := getFlowStoreCookie(uplinkClassifier, gemPortId)
474 //Add Uplink EAPOL Flow
475 uplinkFlowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
476 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530477 log.Errorw("flowId unavailable for UL EAPOL", log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
478 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530479 }
480 var classifierProto *openolt_pb2.Classifier
481 var actionProto *openolt_pb2.Action
482 log.Debugw("Creating UL EAPOL flow", log.Fields{"ul_classifier": uplinkClassifier, "ul_action": uplinkAction, "uplinkFlowId": uplinkFlowId})
483
484 if classifierProto = makeOpenOltClassifierField(uplinkClassifier); classifierProto == nil {
485 log.Error("Error in making classifier protobuf for ul flow")
486 return
487 }
488 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
489 if actionProto = makeOpenOltActionField(uplinkAction); actionProto == nil {
490 log.Error("Error in making action protobuf for ul flow")
491 return
492 }
493 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530494 networkIntfId, err := f.getNniIntfID()
495 if err != nil {
496 log.Error("Error in getting NNI interface ID, Failed to add EAPOL Flow")
497 return
498 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530499 upstreamFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
500 OnuId: int32(onuId),
501 UniId: int32(uniId),
502 FlowId: uplinkFlowId,
503 FlowType: UPSTREAM,
504 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530505 NetworkIntfId: int32(networkIntfId),
manikkaraj kbf256be2019-03-25 00:13:48 +0530506 GemportId: int32(gemPortId),
507 Classifier: classifierProto,
508 Action: actionProto,
509 Priority: int32(logicalFlow.Priority),
510 Cookie: logicalFlow.Cookie,
511 PortNo: portNo}
512 if ok := f.addFlowToDevice(&upstreamFlow); ok {
513 log.Debug("EAPOL UL flow added to device successfully")
514 flowsToKVStore := f.getUpdatedFlowInfo(&upstreamFlow, flowStoreCookie, "EAPOL")
515 if err := f.updateFlowInfoToKVStore(upstreamFlow.AccessIntfId,
516 upstreamFlow.OnuId,
517 upstreamFlow.UniId,
518 upstreamFlow.FlowId, flowsToKVStore); err != nil {
519 log.Errorw("Error uploading EAPOL UL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
520 return
521 }
522 }
523
524 if vlanId == DEFAULT_MGMT_VLAN {
525 /* Add Downstream EAPOL Flow, Only for first EAP flow (BAL
526 # requirement)
527 # On one of the platforms (Broadcom BAL), when same DL classifier
528 # vlan was used across multiple ONUs, eapol flow re-adds after
529 # flow delete (cases of onu reboot/disable) fails.
530 # In order to generate unique vlan, a combination of intf_id
531 # onu_id and uniId is used.
532 # uniId defaults to 0, so add 1 to it.
533 */
534 log.Debugw("Creating DL EAPOL flow with default vlan", log.Fields{"vlan": vlanId})
535 specialVlanDlFlow := 4090 - intfId*onuId*(uniId+1)
536 // Assert that we do not generate invalid vlans under no condition
537 if specialVlanDlFlow <= 2 {
538 log.Fatalw("invalid-vlan-generated", log.Fields{"vlan": specialVlanDlFlow})
539 return
540 }
541 log.Debugw("specialVlanEAPOLDlFlow:", log.Fields{"dl_vlan": specialVlanDlFlow})
542 // Fill Classfier
543 downlinkClassifier[PACKET_TAG_TYPE] = SINGLE_TAG
544 downlinkClassifier[VLAN_VID] = uint32(specialVlanDlFlow)
545 // Fill action
546 downlinkAction[PUSH_VLAN] = true
547 downlinkAction[VLAN_VID] = vlanId
548 flowStoreCookie := getFlowStoreCookie(downlinkClassifier, gemPortId)
549 downlinkFlowId, err := f.resourceMgr.GetFlowID(intfId, onuId, uniId, flowStoreCookie, "")
550 if err != nil {
Manikkaraj k884c1242019-04-11 16:26:42 +0530551 log.Errorw("flowId unavailable for DL EAPOL",
manikkaraj kbf256be2019-03-25 00:13:48 +0530552 log.Fields{"intfId": intfId, "onuId": onuId, "flowStoreCookie": flowStoreCookie})
553 return
554 }
555 log.Debugw("Creating DL EAPOL flow",
556 log.Fields{"dl_classifier": downlinkClassifier, "dl_action": downlinkAction, "downlinkFlowId": downlinkFlowId})
557 if classifierProto = makeOpenOltClassifierField(downlinkClassifier); classifierProto == nil {
558 log.Error("Error in making classifier protobuf for downlink flow")
559 return
560 }
561 if actionProto = makeOpenOltActionField(downlinkAction); actionProto == nil {
562 log.Error("Error in making action protobuf for dl flow")
563 return
564 }
565 // Downstream flow in grpc protobuf
566 downstreamFlow = openolt_pb2.Flow{AccessIntfId: int32(intfId),
567 OnuId: int32(onuId),
568 UniId: int32(uniId),
569 FlowId: downlinkFlowId,
570 FlowType: DOWNSTREAM,
571 AllocId: int32(allocId),
Devmalya Paul0099c9c2019-06-10 14:40:30 +0530572 NetworkIntfId: int32(networkIntfId),
manikkaraj kbf256be2019-03-25 00:13:48 +0530573 GemportId: int32(gemPortId),
574 Classifier: classifierProto,
575 Action: actionProto,
576 Priority: int32(logicalFlow.Priority),
577 Cookie: logicalFlow.Cookie,
578 PortNo: portNo}
579 if ok := f.addFlowToDevice(&downstreamFlow); ok {
580 log.Debug("EAPOL DL flow added to device successfully")
581 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamFlow, flowStoreCookie, "")
582 if err := f.updateFlowInfoToKVStore(downstreamFlow.AccessIntfId,
583 downstreamFlow.OnuId,
584 downstreamFlow.UniId,
585 downstreamFlow.FlowId, flowsToKVStore); err != nil {
586 log.Errorw("Error uploading EAPOL DL flow into KV store", log.Fields{"flow": upstreamFlow, "error": err})
587 return
588 }
589 }
590 } else {
591 log.Infow("EAPOL flow with non-default mgmt vlan is not supported", log.Fields{"vlanId": vlanId})
592 return
593 }
594 log.Debugw("Added EAPOL flows to device successfully", log.Fields{"flow": logicalFlow})
595}
596
597func makeOpenOltClassifierField(classifierInfo map[string]interface{}) *openolt_pb2.Classifier {
598 var classifier openolt_pb2.Classifier
599 if etherType, ok := classifierInfo[ETH_TYPE]; ok {
600 classifier.EthType = etherType.(uint32)
601 }
602 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
603 classifier.IpProto = ipProto.(uint32)
604 }
605 if vlanId, ok := classifierInfo[VLAN_VID]; ok {
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400606 classifier.OVid = (vlanId.(uint32)) & 0xFFF
manikkaraj kbf256be2019-03-25 00:13:48 +0530607 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530608 if metadata, ok := classifierInfo[METADATA]; ok { // TODO: Revisit
609 classifier.IVid = uint32(metadata.(uint64))
manikkaraj kbf256be2019-03-25 00:13:48 +0530610 }
611 if vlanPcp, ok := classifierInfo[VLAN_PCP]; ok {
612 classifier.OPbits = vlanPcp.(uint32)
613 }
614 if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
615 classifier.SrcPort = udpSrc.(uint32)
616 }
617 if udpDst, ok := classifierInfo[UDP_DST]; ok {
618 classifier.DstPort = udpDst.(uint32)
619 }
620 if ipv4Dst, ok := classifierInfo[IPV4_DST]; ok {
621 classifier.DstIp = ipv4Dst.(uint32)
622 }
623 if ipv4Src, ok := classifierInfo[IPV4_SRC]; ok {
624 classifier.SrcIp = ipv4Src.(uint32)
625 }
626 if pktTagType, ok := classifierInfo[PACKET_TAG_TYPE]; ok {
627 if pktTagType.(string) == SINGLE_TAG {
628 classifier.PktTagType = SINGLE_TAG
629 } else if pktTagType.(string) == DOUBLE_TAG {
630 classifier.PktTagType = DOUBLE_TAG
631 } else if pktTagType.(string) == UNTAGGED {
632 classifier.PktTagType = UNTAGGED
633 } else {
634 log.Error("Invalid tag type in classifier") // should not hit
635 return nil
636 }
637 }
638 return &classifier
639}
640
641func makeOpenOltActionField(actionInfo map[string]interface{}) *openolt_pb2.Action {
642 var actionCmd openolt_pb2.ActionCmd
643 var action openolt_pb2.Action
644 action.Cmd = &actionCmd
645 if _, ok := actionInfo[POP_VLAN]; ok {
646 action.OVid = actionInfo[VLAN_VID].(uint32)
647 action.Cmd.RemoveOuterTag = true
648 } else if _, ok := actionInfo[PUSH_VLAN]; ok {
649 action.OVid = actionInfo[VLAN_VID].(uint32)
650 action.Cmd.AddOuterTag = true
651 } else if _, ok := actionInfo[TRAP_TO_HOST]; ok {
652 action.Cmd.TrapToHost = actionInfo[TRAP_TO_HOST].(bool)
653 } else {
654 log.Errorw("Invalid-action-field", log.Fields{"action": actionInfo})
655 return nil
656 }
657 return &action
658}
659
660func (f *OpenOltFlowMgr) getTPpath(intfId uint32, uni string) string {
661 /*
662 FIXME
663 Should get Table id form the flow, as of now hardcoded to DEFAULT_TECH_PROFILE_TABLE_ID (64)
664 'tp_path' contains the suffix part of the tech_profile_instance path. The prefix to the 'tp_path' should be set to
665 TechProfile.KV_STORE_TECH_PROFILE_PATH_PREFIX by the ONU adapter.
666 */
667 return f.techprofile[intfId].GetTechProfileInstanceKVPath(tp.DEFAULT_TECH_PROFILE_TABLE_ID, uni)
668}
669
670func getFlowStoreCookie(classifier map[string]interface{}, gemPortId uint32) uint64 {
671 if len(classifier) == 0 { // should never happen
672 log.Error("Invalid classfier object")
673 return 0
674 }
675 var jsonData []byte
676 var flowString string
677 var err error
678 // TODO: Do we need to marshall ??
679 if jsonData, err = json.Marshal(classifier); err != nil {
680 log.Error("Failed to encode classifier")
681 return 0
682 }
683 flowString = string(jsonData)
684 if gemPortId != 0 {
685 flowString = fmt.Sprintf("%s%s", string(jsonData), string(gemPortId))
686 }
687 h := md5.New()
688 h.Write([]byte(flowString))
689 hash := big.NewInt(0)
690 hash.SetBytes(h.Sum(nil))
691 return hash.Uint64()
692}
693
manikkaraj k17652a72019-05-06 09:06:36 -0400694func (f *OpenOltFlowMgr) getUpdatedFlowInfo(flow *openolt_pb2.Flow, flowStoreCookie uint64, flowCategory string) *[]rsrcMgr.FlowInfo {
695 var flows []rsrcMgr.FlowInfo = []rsrcMgr.FlowInfo{rsrcMgr.FlowInfo{Flow: flow, FlowCategory: flowCategory, FlowStoreCookie: flowStoreCookie}}
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400696 var intfId uint32
697 /* For flows which trap out of the NNI, the AccessIntfId is invalid
698 (set to -1). In such cases, we need to refer to the NetworkIntfId .
699 */
700 if flow.AccessIntfId != -1 {
701 intfId = uint32(flow.AccessIntfId)
702 } else {
703 intfId = uint32(flow.NetworkIntfId)
704 }
705 // Get existing flows matching flowid for given subscriber from KV store
706 existingFlows := f.resourceMgr.GetFlowIDInfo(intfId, uint32(flow.OnuId), uint32(flow.UniId), flow.FlowId)
manikkaraj k17652a72019-05-06 09:06:36 -0400707 if existingFlows != nil {
708 log.Debugw("Flow exists for given flowID, appending it to current flow", log.Fields{"flowID": flow.FlowId})
709 for _, f := range *existingFlows {
710 flows = append(flows, f)
711 }
712 }
713 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 +0530714 return &flows
715}
716
manikkaraj k17652a72019-05-06 09:06:36 -0400717func (f *OpenOltFlowMgr) updateFlowInfoToKVStore(intfId int32, onuId int32, uniId int32, flowId uint32, flows *[]rsrcMgr.FlowInfo) error {
718 log.Debugw("Storing flow(s) into KV store", log.Fields{"flows": *flows})
719 if err := f.resourceMgr.UpdateFlowIDInfo(intfId, onuId, uniId, flowId, flows); err != nil {
720 log.Debug("Error while Storing flow into KV store")
721 return err
722 }
723 log.Info("Stored flow(s) into KV store successfully!")
manikkaraj kbf256be2019-03-25 00:13:48 +0530724 return nil
725}
726
727func (f *OpenOltFlowMgr) addFlowToDevice(deviceFlow *openolt_pb2.Flow) bool {
728 log.Debugw("Sending flow to device via grpc", log.Fields{"flow": *deviceFlow})
729 _, err := f.deviceHandler.Client.FlowAdd(context.Background(), deviceFlow)
730 if err != nil {
731 log.Errorw("Failed to Add flow to device", log.Fields{"err": err, "deviceFlow": deviceFlow})
732 return false
733 }
734 log.Debugw("Flow added to device successfuly ", log.Fields{"flow": *deviceFlow})
735 return true
736}
737
738/*func register_flow(deviceFlow *openolt_pb2.Flow, logicalFlow *ofp.OfpFlowStats){
739 //update core flows_proxy : flows_proxy.update('/', flows)
740}
741
742func generateStoredId(flowId uint32, direction string)uint32{
743
744 if direction == UPSTREAM{
745 log.Debug("Upstream flow shifting flowid")
746 return ((0x1 << 15) | flowId)
747 }else if direction == DOWNSTREAM{
748 log.Debug("Downstream flow not shifting flowid")
749 return flowId
750 }else{
751 log.Errorw("Unrecognized direction",log.Fields{"direction": direction})
752 return flowId
753 }
754}
755
756*/
757
758func addLLDPFlow(flow *ofp.OfpFlowStats, portNo uint32) {
759 log.Info("Unimplemented")
760}
761func getUniPortPath(intfId uint32, onuId uint32, uniId uint32) string {
762 return fmt.Sprintf("pon-{%d}/onu-{%d}/uni-{%d}", intfId, onuId, uniId)
763}
764
Manikkaraj k884c1242019-04-11 16:26:42 +0530765func (f *OpenOltFlowMgr) getOnuChildDevice(intfId uint32, onuId uint32) (*voltha.Device, error) {
766 log.Debugw("GetChildDevice", log.Fields{"pon port": intfId, "onuId": onuId})
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400767 parentPortNo := IntfIdToPortNo(intfId, voltha.Port_PON_OLT)
Manikkaraj k884c1242019-04-11 16:26:42 +0530768 onuDevice := f.deviceHandler.GetChildDevice(parentPortNo, onuId)
769 if onuDevice == nil {
770 log.Errorw("onu not found", log.Fields{"intfId": parentPortNo, "onuId": onuId})
771 return nil, errors.New("onu not found")
manikkaraj kbf256be2019-03-25 00:13:48 +0530772 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530773 log.Debugw("Successfully received child device from core", log.Fields{"child_device": *onuDevice})
774 return onuDevice, nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530775}
776
777func findNextFlow(flow *ofp.OfpFlowStats) *ofp.OfpFlowStats {
778 log.Info("Unimplemented")
779 return nil
780}
781
782func getSubscriberVlan(inPort uint32) uint32 {
783 /* For EAPOL case we will use default VLAN , so will implement later if required */
784 log.Info("Unimplemented")
785 return 0
786}
787
788func (f *OpenOltFlowMgr) clear_flows_and_scheduler_for_logical_port(childDevice *voltha.Device, logicalPort *voltha.LogicalPort) {
789 log.Info("Unimplemented")
790}
791
792func (f *OpenOltFlowMgr) AddFlow(flow *ofp.OfpFlowStats) {
793 classifierInfo := make(map[string]interface{}, 0)
794 actionInfo := make(map[string]interface{}, 0)
795 log.Debug("Adding Flow", log.Fields{"flow": flow})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400796 for _, field := range utils.GetOfbFields(flow) {
797 if field.Type == utils.ETH_TYPE {
manikkaraj kbf256be2019-03-25 00:13:48 +0530798 classifierInfo[ETH_TYPE] = field.GetEthType()
799 log.Debug("field-type-eth-type", log.Fields{"classifierInfo[ETH_TYPE]": classifierInfo[ETH_TYPE].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400800 } else if field.Type == utils.IP_PROTO {
manikkaraj kbf256be2019-03-25 00:13:48 +0530801 classifierInfo[IP_PROTO] = field.GetIpProto()
802 log.Debug("field-type-ip-proto", log.Fields{"classifierInfo[IP_PROTO]": classifierInfo[IP_PROTO].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400803 } else if field.Type == utils.IN_PORT {
manikkaraj kbf256be2019-03-25 00:13:48 +0530804 classifierInfo[IN_PORT] = field.GetPort()
805 log.Debug("field-type-in-port", log.Fields{"classifierInfo[IN_PORT]": classifierInfo[IN_PORT].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400806 } else if field.Type == utils.VLAN_VID {
manikkaraj kbf256be2019-03-25 00:13:48 +0530807 classifierInfo[VLAN_VID] = field.GetVlanVid()
808 log.Debug("field-type-vlan-vid", log.Fields{"classifierInfo[VLAN_VID]": classifierInfo[VLAN_VID].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400809 } else if field.Type == utils.VLAN_PCP {
manikkaraj kbf256be2019-03-25 00:13:48 +0530810 classifierInfo[VLAN_PCP] = field.GetVlanPcp()
811 log.Debug("field-type-vlan-pcp", log.Fields{"classifierInfo[VLAN_PCP]": classifierInfo[VLAN_PCP].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400812 } else if field.Type == utils.UDP_DST {
manikkaraj kbf256be2019-03-25 00:13:48 +0530813 classifierInfo[UDP_DST] = field.GetUdpDst()
814 log.Debug("field-type-udp-dst", log.Fields{"classifierInfo[UDP_DST]": classifierInfo[UDP_DST].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400815 } else if field.Type == utils.UDP_SRC {
manikkaraj kbf256be2019-03-25 00:13:48 +0530816 classifierInfo[UDP_SRC] = field.GetUdpSrc()
817 log.Debug("field-type-udp-src", log.Fields{"classifierInfo[UDP_SRC]": classifierInfo[UDP_SRC].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400818 } else if field.Type == utils.IPV4_DST {
manikkaraj kbf256be2019-03-25 00:13:48 +0530819 classifierInfo[IPV4_DST] = field.GetIpv4Dst()
820 log.Debug("field-type-ipv4-dst", log.Fields{"classifierInfo[IPV4_DST]": classifierInfo[IPV4_DST].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400821 } else if field.Type == utils.IPV4_SRC {
manikkaraj kbf256be2019-03-25 00:13:48 +0530822 classifierInfo[IPV4_SRC] = field.GetIpv4Src()
823 log.Debug("field-type-ipv4-src", log.Fields{"classifierInfo[IPV4_SRC]": classifierInfo[IPV4_SRC].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400824 } else if field.Type == utils.METADATA {
manikkaraj kbf256be2019-03-25 00:13:48 +0530825 classifierInfo[METADATA] = field.GetTableMetadata()
826 log.Debug("field-type-metadata", log.Fields{"classifierInfo[METADATA]": classifierInfo[METADATA].(uint64)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400827 } else if field.Type == utils.TUNNEL_ID {
manikkaraj k17652a72019-05-06 09:06:36 -0400828 classifierInfo[TUNNEL_ID] = field.GetTunnelId()
829 log.Debug("field-type-tunnelId", log.Fields{"classifierInfo[TUNNEL_ID]": classifierInfo[TUNNEL_ID].(uint64)})
manikkaraj kbf256be2019-03-25 00:13:48 +0530830 } else {
831 log.Errorw("Un supported field type", log.Fields{"type": field.Type})
832 return
833 }
834 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400835 for _, action := range utils.GetActions(flow) {
836 if action.Type == utils.OUTPUT {
manikkaraj kbf256be2019-03-25 00:13:48 +0530837 if out := action.GetOutput(); out != nil {
838 actionInfo[OUTPUT] = out.GetPort()
839 log.Debugw("action-type-output", log.Fields{"out_port": actionInfo[OUTPUT].(uint32)})
840 } else {
841 log.Error("Invalid output port in action")
842 return
843 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400844 } else if action.Type == utils.POP_VLAN {
manikkaraj kbf256be2019-03-25 00:13:48 +0530845 actionInfo[POP_VLAN] = true
846 log.Debugw("action-type-pop-vlan", log.Fields{"in_port": classifierInfo[IN_PORT].(uint32)})
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400847 } else if action.Type == utils.PUSH_VLAN {
manikkaraj kbf256be2019-03-25 00:13:48 +0530848 if out := action.GetPush(); out != nil {
849 if tpid := out.GetEthertype(); tpid != 0x8100 {
850 log.Errorw("Invalid ethertype in push action", log.Fields{"ethertype": actionInfo[PUSH_VLAN].(int32)})
851 } else {
852 actionInfo[PUSH_VLAN] = true
853 actionInfo[TPID] = tpid
854 log.Debugw("action-type-push-vlan",
855 log.Fields{"push_tpid": actionInfo[TPID].(uint32), "in_port": classifierInfo[IN_PORT].(uint32)})
856 }
857 }
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400858 } else if action.Type == utils.SET_FIELD {
manikkaraj kbf256be2019-03-25 00:13:48 +0530859 if out := action.GetSetField(); out != nil {
860 if field := out.GetField(); field != nil {
861 if ofClass := field.GetOxmClass(); ofClass != ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
862 log.Errorw("Invalid openflow class", log.Fields{"class": ofClass})
863 return
864 }
865 /*log.Debugw("action-type-set-field",log.Fields{"field": field, "in_port": classifierInfo[IN_PORT].(uint32)})*/
866 if ofbField := field.GetOfbField(); ofbField != nil {
867 if fieldtype := ofbField.GetType(); fieldtype == ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID {
868 if vlan := ofbField.GetVlanVid(); vlan != 0 {
869 actionInfo[VLAN_VID] = vlan & 0xfff
870 log.Debugw("action-set-vlan-vid", log.Fields{"actionInfo[VLAN_VID]": actionInfo[VLAN_VID].(uint32)})
871 } else {
872 log.Error("No Invalid vlan id in set vlan-vid action")
873 }
874 } else {
875 log.Errorw("unsupported-action-set-field-type", log.Fields{"type": fieldtype})
876 }
877 }
878 }
879 }
880 } else {
881 log.Errorw("Un supported action type", log.Fields{"type": action.Type})
882 return
883 }
884 }
manikkaraj k17652a72019-05-06 09:06:36 -0400885 /* Controller bound trap flows */
886 if isControllerFlow := IsControllerBoundFlow(actionInfo[OUTPUT].(uint32)); isControllerFlow {
887 log.Debug("Controller bound trap flows, getting inport from tunnelid")
888 /* Get UNI port/ IN Port from tunnel ID field for upstream controller bound flows */
889 if portType := IntfIdToPortTypeName(classifierInfo[IN_PORT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400890 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -0400891 classifierInfo[IN_PORT] = uniPort
892 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 +0530893 } else {
manikkaraj k17652a72019-05-06 09:06:36 -0400894 log.Error("upstream pon-to-controller-flow, NO-inport-in-tunnelid")
895 return
manikkaraj kbf256be2019-03-25 00:13:48 +0530896 }
897 }
manikkaraj k17652a72019-05-06 09:06:36 -0400898 } else {
899 log.Debug("Non-Controller flows, getting uniport from tunnelid")
900 // Downstream flow from NNI to PON port , Use tunnel ID as new OUT port / UNI port
901 if portType := IntfIdToPortTypeName(actionInfo[OUTPUT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400902 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -0400903 actionInfo[OUTPUT] = uniPort
904 log.Debugw("downstream-nni-to-pon-port-flow, outport-in-tunnelid", log.Fields{"newOutPort": actionInfo[OUTPUT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
905 } else {
906 log.Debug("downstream-nni-to-pon-port-flow, no-outport-in-tunnelid", log.Fields{"InPort": classifierInfo[IN_PORT].(uint32), "outPort": actionInfo[OUTPUT].(uint32)})
907 return
908 }
909 // Upstream flow from PON to NNI port , Use tunnel ID as new IN port / UNI port
910 } else if portType := IntfIdToPortTypeName(classifierInfo[IN_PORT].(uint32)); portType == voltha.Port_PON_OLT {
Matt Jeannereta93dbed2019-05-17 12:40:05 -0400911 if uniPort := utils.GetChildPortFromTunnelId(flow); uniPort != 0 {
manikkaraj k17652a72019-05-06 09:06:36 -0400912 classifierInfo[IN_PORT] = uniPort
913 log.Debugw("upstream-pon-to-nni-port-flow, inport-in-tunnelid", log.Fields{"newInPort": actionInfo[OUTPUT].(uint32),
914 "outport": actionInfo[OUTPUT].(uint32)})
915 } else {
916 log.Debug("upstream-pon-to-nni-port-flow, no-inport-in-tunnelid", log.Fields{"InPort": classifierInfo[IN_PORT].(uint32),
917 "outPort": actionInfo[OUTPUT].(uint32)})
918 return
919 }
920 }
921 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530922 log.Infow("Flow ports", log.Fields{"classifierInfo_inport": classifierInfo[IN_PORT], "action_output": actionInfo[OUTPUT]})
923 portNo, intfId, onuId, uniId := ExtractAccessFromFlow(classifierInfo[IN_PORT].(uint32), actionInfo[OUTPUT].(uint32))
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400924 if ipProto, ok := classifierInfo[IP_PROTO]; ok {
925 if ipProto.(uint32) == IP_PROTO_DHCP {
926 if udpSrc, ok := classifierInfo[UDP_SRC]; ok {
927 if udpSrc.(uint32) == uint32(67) {
928 log.Debug("trap-dhcp-from-nni-flow")
929 f.addDHCPTrapFlowOnNNI(flow, classifierInfo, portNo)
930 return
931 }
932 }
933 }
934 }
manikkaraj kbf256be2019-03-25 00:13:48 +0530935 f.divideAndAddFlow(intfId, onuId, uniId, portNo, classifierInfo, actionInfo, flow)
936}
937
Manikkaraj k884c1242019-04-11 16:26:42 +0530938func (f *OpenOltFlowMgr) sendTPDownloadMsgToChild(intfId uint32, onuId uint32, uniId uint32, uni string) error {
manikkaraj kbf256be2019-03-25 00:13:48 +0530939
Manikkaraj k884c1242019-04-11 16:26:42 +0530940 onuDevice, err := f.getOnuChildDevice(intfId, onuId)
941 if err != nil {
942 log.Errorw("Error while fetching Child device from core", log.Fields{"onuId": onuId})
943 return err
manikkaraj kbf256be2019-03-25 00:13:48 +0530944 }
Manikkaraj k884c1242019-04-11 16:26:42 +0530945 log.Debugw("Got child device from OLT device handler", log.Fields{"device": *onuDevice})
manikkaraj k17652a72019-05-06 09:06:36 -0400946
947 tpPath := f.getTPpath(intfId, uni)
948 tpDownloadMsg := &ic.InterAdapterTechProfileDownloadMessage{UniId: uniId, Path: tpPath}
949 log.Infow("Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": *tpDownloadMsg})
950 sendErr := f.deviceHandler.AdapterProxy.SendInterAdapterMessage(context.Background(),
951 tpDownloadMsg,
952 ic.InterAdapterMessageType_TECH_PROFILE_DOWNLOAD_REQUEST,
953 f.deviceHandler.deviceType,
954 onuDevice.Type,
955 onuDevice.Id,
956 onuDevice.ProxyAddress.DeviceId, "")
957 if sendErr != nil {
958 log.Errorw("send techprofile-download request error", log.Fields{"fromAdapter": f.deviceHandler.deviceType,
959 "toAdapter": onuDevice.Type, "onuId": onuDevice.Id,
960 "proxyDeviceId": onuDevice.ProxyAddress.DeviceId})
961 return sendErr
962 }
963 log.Debugw("success Sending Load-tech-profile-request-to-brcm-onu-adapter", log.Fields{"msg": tpDownloadMsg})
Manikkaraj k884c1242019-04-11 16:26:42 +0530964 return nil
manikkaraj kbf256be2019-03-25 00:13:48 +0530965}
manikkaraj k9eb6cac2019-05-09 12:32:03 -0400966
967// This function adds onu info to cache
968func (f *OpenOltFlowMgr) UpdateOnuInfo(intfID uint32, onuID uint32, serialNum string) {
969 onu := onuInfo{intfId: intfID, onuId: onuID, serialNumber: serialNum}
970 onuIDkey := onuIdKey{intfId: intfID, onuId: onuID}
971 f.onuIds[onuIDkey] = onu
972 log.Debugw("Updated onuinfo", log.Fields{"intfID": intfID, "onuID": onuID, "serialNum": serialNum})
973}
974
975// This function stores adds GEMport to ONU map
976func (f *OpenOltFlowMgr) addGemPortToOnuInfoMap(intfId uint32, onuId uint32, gemPort uint32) {
977 onuIDkey := onuIdKey{intfId: intfId, onuId: onuId}
978 if val, ok := f.onuIds[onuIDkey]; ok {
979 onuInfo := val
980 gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPort}
981 f.onuGemPortIds[gemPortKey] = onuInfo
982 log.Debugw("Cached Gemport to Onuinfo map", log.Fields{"GemPort": gemPort, "intfId": onuInfo.intfId, "onuId": onuInfo.onuId})
983 return
984 }
985 log.Errorw("OnuInfo not found", log.Fields{"intfId": intfId, "onuId": onuId, "gemPort": gemPort})
986}
987
988// This function Lookup maps by serialNumber or (intfId, gemPort)
989// Returns OnuID,nil if found or set 0,error if no onuId is found for serialNumber or (intfId, gemPort)
990func (f *OpenOltFlowMgr) getOnuIdfromGemPortMap(serialNumber string, intfId uint32, gemPortId uint32) (uint32, error) {
991 log.Debugw("Getting ONU ID from GEM port and PON port", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPortId": gemPortId})
992 if serialNumber != "" {
993 if onuInfo, ok := f.onuSerialNumbers[serialNumber]; ok {
994 return onuInfo.onuId, nil
995 }
996 } else {
997 gemPortKey := gemPortKey{intfId: intfId, gemPort: gemPortId}
998 if onuInfo, ok := f.onuGemPortIds[gemPortKey]; ok {
999 log.Debugw("Retrived onu info from access", log.Fields{"intfId": intfId, "gemPortId": gemPortId, "onuId": onuInfo.onuId})
1000 return onuInfo.onuId, nil
1001 }
1002 }
1003 log.Errorw("ONU ID is not found", log.Fields{"serialNumber": serialNumber, "intfId": intfId, "gemPort": gemPortId})
1004 return uint32(0), errors.New("Key Error ,ONU ID is not found") // ONU ID 0 is not a valid one
1005}
1006
1007// This function computes logical port UNI/NNI port from packet-in indication and returns the same
1008func (f *OpenOltFlowMgr) GetLogicalPortFromPacketIn(packetIn *openolt_pb2.PacketIndication) (uint32, error) {
1009 var logicalPortNum uint32
1010 var onuId uint32
1011 var err error
1012
1013 if packetIn.IntfType == "pon" {
1014 // packet indication does not have serial number , so sending as nil
1015 if onuId, err = f.getOnuIdfromGemPortMap("", packetIn.IntfId, packetIn.GemportId); err != nil {
1016 log.Errorw("Unable to get ONU ID from GEM/PON port", log.Fields{"pon port": packetIn.IntfId, "gemport": packetIn.GemportId})
1017 return logicalPortNum, err
1018 }
1019 if packetIn.PortNo != 0 {
1020 logicalPortNum = packetIn.PortNo
1021 } else {
1022 uniId := uint32(0) // FIXME - multi-uni support
1023 logicalPortNum = MkUniPortNum(packetIn.IntfId, onuId, uniId)
1024 }
1025 // Store the gem port through which the packet_in came. Use the same gem port for packet_out
1026 pktInkey := packetInInfoKey{intfId: packetIn.IntfId, onuId: onuId, logicalPort: logicalPortNum}
1027 f.packetInGemPort[pktInkey] = packetIn.GemportId
1028 } else if packetIn.IntfType == "nni" {
1029 logicalPortNum = IntfIdToPortNo(packetIn.IntfId, voltha.Port_ETHERNET_NNI)
1030 }
1031 log.Debugw("Retrieved logicalport from packet-in", log.Fields{"logicalPortNum": logicalPortNum, "IntfType": packetIn.IntfType})
1032 return logicalPortNum, nil
1033}
1034
1035func (f *OpenOltFlowMgr) GetPacketOutGemPortId(intfId uint32, onuId uint32, portNum uint32) (uint32, error) {
1036 var gemPortId uint32
1037 var err error
1038 key := packetInInfoKey{intfId: intfId, onuId: onuId, logicalPort: portNum}
1039 if val, ok := f.packetInGemPort[key]; ok {
1040 gemPortId = val
1041 } else {
1042 log.Errorw("Key-Error while fetching packet-out GEM port", log.Fields{"key": key})
1043 err = errors.New("Key-Error while fetching packet-out GEM port")
1044 }
1045 return gemPortId, err
1046}
1047
1048func (f *OpenOltFlowMgr) addDHCPTrapFlowOnNNI(logicalFlow *ofp.OfpFlowStats, classifier map[string]interface{}, portNo uint32) {
1049 log.Debug("Adding trap-dhcp-of-nni-flow")
1050 action := make(map[string]interface{})
1051 classifier[PACKET_TAG_TYPE] = DOUBLE_TAG
1052 action[TRAP_TO_HOST] = true
1053 /* We manage flowId resource pool on per PON port basis.
1054 Since this situation is tricky, as a hack, we pass the NNI port
1055 index (network_intf_id) as PON port Index for the flowId resource
1056 pool. Also, there is no ONU Id available for trapping DHCP packets
1057 on NNI port, use onu_id as -1 (invalid)
1058 ****************** CAVEAT *******************
1059 This logic works if the NNI Port Id falls within the same valid
1060 range of PON Port Ids. If this doesn't work for some OLT Vendor
1061 we need to have a re-look at this.
1062 *********************************************
1063 */
1064 onuId := -1
1065 uniId := -1
1066 gemPortId := -1
1067 allocId := -1
Devmalya Paul0099c9c2019-06-10 14:40:30 +05301068 networkInterfaceId, err := f.getNniIntfID()
1069 if err != nil {
1070 log.Error("Error in getting NNI interface ID, Failed to add DHCP Trap flow on NNI")
1071 return
1072 }
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001073 flowStoreCookie := getFlowStoreCookie(classifier, uint32(0))
1074 if present := f.resourceMgr.IsFlowCookieOnKVStore(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie); present {
1075 log.Debug("Flow-exists--not-re-adding")
1076 return
1077 }
1078 flowId, err := f.resourceMgr.GetFlowID(uint32(networkInterfaceId), uint32(onuId), uint32(uniId), flowStoreCookie, "")
1079 if err != nil {
1080 log.Errorw("Flow id unavailable for DHCP traponNNI flow", log.Fields{"error": err})
1081 return
1082 }
1083 var classifierProto *openolt_pb2.Classifier
1084 var actionProto *openolt_pb2.Action
1085 if classifierProto = makeOpenOltClassifierField(classifier); classifierProto == nil {
1086 log.Error("Error in making classifier protobuf for dhcp trap on nni flow")
1087 return
1088 }
1089 log.Debugw("Created classifier proto", log.Fields{"classifier": *classifierProto})
1090 if actionProto = makeOpenOltActionField(action); actionProto == nil {
1091 log.Error("Error in making action protobuf for dhcp trap on nni flow")
1092 return
1093 }
1094 log.Debugw("Created action proto", log.Fields{"action": *actionProto})
1095 downstreamflow := openolt_pb2.Flow{AccessIntfId: int32(-1), // AccessIntfId not required
1096 OnuId: int32(onuId), // OnuId not required
1097 UniId: int32(uniId), // UniId not used
1098 FlowId: flowId,
1099 FlowType: DOWNSTREAM,
Devmalya Paul0099c9c2019-06-10 14:40:30 +05301100 AllocId: int32(allocId), // AllocId not used
1101 NetworkIntfId: int32(networkInterfaceId),
1102 GemportId: int32(gemPortId), // GemportId not used
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001103 Classifier: classifierProto,
1104 Action: actionProto,
1105 Priority: int32(logicalFlow.Priority),
1106 Cookie: logicalFlow.Cookie,
1107 PortNo: portNo}
1108 if ok := f.addFlowToDevice(&downstreamflow); ok {
1109 log.Debug("DHCP trap on NNI flow added to device successfully")
1110 flowsToKVStore := f.getUpdatedFlowInfo(&downstreamflow, flowStoreCookie, "")
1111 if err := f.updateFlowInfoToKVStore(int32(networkInterfaceId),
1112 int32(onuId),
1113 int32(uniId),
1114 flowId, flowsToKVStore); err != nil {
1115 log.Errorw("Error uploading DHCP DL flow into KV store", log.Fields{"flow": downstreamflow, "error": err})
1116 }
1117 }
1118 return
1119}
Devmalya Paul0099c9c2019-06-10 14:40:30 +05301120
1121func (f *OpenOltFlowMgr) getNniIntfID() (int32, error) {
1122 device, err := f.deviceHandler.coreProxy.GetDevice(nil, f.deviceHandler.deviceId, f.deviceHandler.deviceId)
1123 if err != nil {
1124 log.Errorw("Failed to get device", log.Fields{"device-id": f.deviceHandler.deviceId})
1125 return -1, err
1126 }
1127 var portNum uint32
1128 for _, port := range device.Ports {
1129 if port.Type == voltha.Port_ETHERNET_NNI {
1130 portNum = port.PortNo
1131 break
1132 }
1133 }
1134
1135 nniIntfId := IntfIdFromNniPortNum(portNum)
1136 log.Debugw("NNI interface Id", log.Fields{"intf-id": nniIntfId})
1137 return int32(nniIntfId), nil
1138}