blob: 1bb5aaf46f253a9295a2a9aaf03d2fd48aecf90e [file] [log] [blame]
Girish Gowdra64503432020-01-07 10:59:10 +05301/*
2 * Copyright 2019-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
17//Package resourcemanager provides the utility for managing resources
18package core
19
20import (
21 "errors"
22 "fmt"
23 "strconv"
24 "strings"
25
26 "github.com/opencord/voltha-lib-go/v2/pkg/log"
27 ponrmgr "github.com/opencord/voltha-lib-go/v2/pkg/ponresourcemanager"
28 "github.com/opencord/voltha-protos/v2/go/openolt"
29)
30
31func init() {
32 _, _ = log.AddPackage(log.JSON, log.DebugLevel, nil)
33}
34
35// OpenOltResourceMgr holds resource related information as provided below for each field
36type OpenOltResourceMgr struct {
37 deviceInfo *openolt.DeviceInfo
38 // array of pon resource managers per interface technology
39 ResourceMgrs map[uint32]*ponrmgr.PONResourceManager
40}
41
42// NewResourceMgr init a New resource manager instance which in turn instantiates pon resource manager
43// instances according to technology. Initializes the default resource ranges for all
44// the resources.
45func NewResourceMgr(deviceID string, KVStoreHostPort string, kvStoreType string, deviceType string, devInfo *openolt.DeviceInfo) *OpenOltResourceMgr {
46 var ResourceMgr OpenOltResourceMgr
47 log.Debugf("Init new resource manager")
48
49 ResourceMgr.deviceInfo = devInfo
50
51 Ranges := make(map[string]*openolt.DeviceInfo_DeviceResourceRanges)
52 RsrcMgrsByTech := make(map[string]*ponrmgr.PONResourceManager)
53 ResourceMgr.ResourceMgrs = make(map[uint32]*ponrmgr.PONResourceManager)
54
55 // TODO self.args = registry('main').get_args()
56
57 /*
58 If a legacy driver returns protobuf without any ranges,s synthesize one from
59 the legacy global per-device information. This, in theory, is temporary until
60 the legacy drivers are upgrade to support pool ranges.
61 */
62 if devInfo.Ranges == nil {
63 var ranges openolt.DeviceInfo_DeviceResourceRanges
64 ranges.Technology = devInfo.GetTechnology()
65
66 NumPONPorts := devInfo.GetPonPorts()
67 var index uint32
68 for index = 0; index < NumPONPorts; index++ {
69 ranges.IntfIds = append(ranges.IntfIds, index)
70 }
71
72 var Pool openolt.DeviceInfo_DeviceResourceRanges_Pool
73 Pool.Type = openolt.DeviceInfo_DeviceResourceRanges_Pool_ONU_ID
74 Pool.Start = devInfo.OnuIdStart
75 Pool.End = devInfo.OnuIdEnd
76 Pool.Sharing = openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF
77 onuPool := Pool
78 ranges.Pools = append(ranges.Pools, &onuPool)
79
80 Pool.Type = openolt.DeviceInfo_DeviceResourceRanges_Pool_ALLOC_ID
81 Pool.Start = devInfo.AllocIdStart
82 Pool.End = devInfo.AllocIdEnd
83 Pool.Sharing = openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH
84 allocPool := Pool
85 ranges.Pools = append(ranges.Pools, &allocPool)
86
87 Pool.Type = openolt.DeviceInfo_DeviceResourceRanges_Pool_GEMPORT_ID
88 Pool.Start = devInfo.GemportIdStart
89 Pool.End = devInfo.GemportIdEnd
90 Pool.Sharing = openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH
91 gemPool := Pool
92 ranges.Pools = append(ranges.Pools, &gemPool)
93
94 Pool.Type = openolt.DeviceInfo_DeviceResourceRanges_Pool_FLOW_ID
95 Pool.Start = devInfo.FlowIdStart
96 Pool.End = devInfo.FlowIdEnd
97 Pool.Sharing = openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH
98 ranges.Pools = append(ranges.Pools, &Pool)
99 // Add to device info
100 devInfo.Ranges = append(devInfo.Ranges, &ranges)
101 }
102
103 // Create a separate Resource Manager instance for each range. This assumes that
104 // each technology is represented by only a single range
105 var GlobalPONRsrcMgr *ponrmgr.PONResourceManager
106 var err error
107 IPPort := strings.Split(KVStoreHostPort, ":")
108 for _, TechRange := range devInfo.Ranges {
109 technology := TechRange.Technology
110 log.Debugf("Device info technology %s", technology)
111 Ranges[technology] = TechRange
112 port, _ := strconv.Atoi(IPPort[1])
113 RsrcMgrsByTech[technology], err = ponrmgr.NewPONResourceManager(technology, deviceType, deviceID,
114 kvStoreType, IPPort[0], port)
115 if err != nil {
116 log.Errorf("Failed to create pon resource manager instance for technology %s", technology)
117 return nil
118 }
119 // resource_mgrs_by_tech[technology] = resource_mgr
120 if GlobalPONRsrcMgr == nil {
121 GlobalPONRsrcMgr = RsrcMgrsByTech[technology]
122 }
123 for _, IntfID := range TechRange.IntfIds {
124 ResourceMgr.ResourceMgrs[(IntfID)] = RsrcMgrsByTech[technology]
125 }
126 // self.initialize_device_resource_range_and_pool(resource_mgr, global_resource_mgr, arange)
127 InitializeDeviceResourceRangeAndPool(RsrcMgrsByTech[technology], GlobalPONRsrcMgr,
128 TechRange, devInfo)
129 }
130 // After we have initialized resource ranges, initialize the
131 // resource pools accordingly.
132 for _, PONRMgr := range RsrcMgrsByTech {
133 _ = PONRMgr.InitDeviceResourcePool()
134 }
135 log.Info("Initialization of resource manager success!")
136 return &ResourceMgr
137}
138
139// InitializeDeviceResourceRangeAndPool initializes the resource range pool according to the sharing type, then apply
140// device specific information. If KV doesn't exist
141// or is broader than the device, the device's information will
142// dictate the range limits
143func InitializeDeviceResourceRangeAndPool(ponRMgr *ponrmgr.PONResourceManager, globalPONRMgr *ponrmgr.PONResourceManager,
144 techRange *openolt.DeviceInfo_DeviceResourceRanges, devInfo *openolt.DeviceInfo) {
145
146 // init the resource range pool according to the sharing type
147
148 log.Debugf("Resource range pool init for technology %s", ponRMgr.Technology)
149 // first load from KV profiles
150 status := ponRMgr.InitResourceRangesFromKVStore()
151 if !status {
152 log.Debugf("Failed to load resource ranges from KV store for tech %s", ponRMgr.Technology)
153 }
154
155 /*
156 Then apply device specific information. If KV doesn't exist
157 or is broader than the device, the device's information will
158 dictate the range limits
159 */
160 log.Debugf("Using device info to init pon resource ranges for tech", ponRMgr.Technology)
161
162 ONUIDStart := devInfo.OnuIdStart
163 ONUIDEnd := devInfo.OnuIdEnd
164 ONUIDShared := openolt.DeviceInfo_DeviceResourceRanges_Pool_DEDICATED_PER_INTF
165 ONUIDSharedPoolID := uint32(0)
166 AllocIDStart := devInfo.AllocIdStart
167 AllocIDEnd := devInfo.AllocIdEnd
168 AllocIDShared := openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH // TODO EdgeCore/BAL limitation
169 AllocIDSharedPoolID := uint32(0)
170 GEMPortIDStart := devInfo.GemportIdStart
171 GEMPortIDEnd := devInfo.GemportIdEnd
172 GEMPortIDShared := openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH // TODO EdgeCore/BAL limitation
173 GEMPortIDSharedPoolID := uint32(0)
174 FlowIDStart := devInfo.FlowIdStart
175 FlowIDEnd := devInfo.FlowIdEnd
176 FlowIDShared := openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH // TODO EdgeCore/BAL limitation
177 FlowIDSharedPoolID := uint32(0)
178
179 var FirstIntfPoolID uint32
180 var SharedPoolID uint32
181
182 /*
183 * As a zero check is made against SharedPoolID to check whether the resources are shared across all intfs
184 * if resources are shared across interfaces then SharedPoolID is given a positive number.
185 */
186 for _, FirstIntfPoolID = range techRange.IntfIds {
187 // skip the intf id 0
188 if FirstIntfPoolID == 0 {
189 continue
190 }
191 break
192 }
193
194 for _, RangePool := range techRange.Pools {
195 if RangePool.Sharing == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH {
196 SharedPoolID = FirstIntfPoolID
197 } else if RangePool.Sharing == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_SAME_TECH {
198 SharedPoolID = FirstIntfPoolID
199 } else {
200 SharedPoolID = 0
201 }
202 if RangePool.Type == openolt.DeviceInfo_DeviceResourceRanges_Pool_ONU_ID {
203 ONUIDStart = RangePool.Start
204 ONUIDEnd = RangePool.End
205 ONUIDShared = RangePool.Sharing
206 ONUIDSharedPoolID = SharedPoolID
207 } else if RangePool.Type == openolt.DeviceInfo_DeviceResourceRanges_Pool_ALLOC_ID {
208 AllocIDStart = RangePool.Start
209 AllocIDEnd = RangePool.End
210 AllocIDShared = RangePool.Sharing
211 AllocIDSharedPoolID = SharedPoolID
212 } else if RangePool.Type == openolt.DeviceInfo_DeviceResourceRanges_Pool_GEMPORT_ID {
213 GEMPortIDStart = RangePool.Start
214 GEMPortIDEnd = RangePool.End
215 GEMPortIDShared = RangePool.Sharing
216 GEMPortIDSharedPoolID = SharedPoolID
217 } else if RangePool.Type == openolt.DeviceInfo_DeviceResourceRanges_Pool_FLOW_ID {
218 FlowIDStart = RangePool.Start
219 FlowIDEnd = RangePool.End
220 FlowIDShared = RangePool.Sharing
221 FlowIDSharedPoolID = SharedPoolID
222 }
223 }
224
225 log.Debugw("Device info init", log.Fields{"technology": techRange.Technology,
226 "onu_id_start": ONUIDStart, "onu_id_end": ONUIDEnd, "onu_id_shared_pool_id": ONUIDSharedPoolID,
227 "alloc_id_start": AllocIDStart, "alloc_id_end": AllocIDEnd,
228 "alloc_id_shared_pool_id": AllocIDSharedPoolID,
229 "gemport_id_start": GEMPortIDStart, "gemport_id_end": GEMPortIDEnd,
230 "gemport_id_shared_pool_id": GEMPortIDSharedPoolID,
231 "flow_id_start": FlowIDStart,
232 "flow_id_end_idx": FlowIDEnd,
233 "flow_id_shared_pool_id": FlowIDSharedPoolID,
234 "intf_ids": techRange.IntfIds,
235 "uni_id_start": 0,
236 "uni_id_end_idx": 1, /*MaxUNIIDperONU()*/
237 })
238
239 ponRMgr.InitDefaultPONResourceRanges(ONUIDStart, ONUIDEnd, ONUIDSharedPoolID,
240 AllocIDStart, AllocIDEnd, AllocIDSharedPoolID,
241 GEMPortIDStart, GEMPortIDEnd, GEMPortIDSharedPoolID,
242 FlowIDStart, FlowIDEnd, FlowIDSharedPoolID, 0, 1,
243 devInfo.PonPorts, techRange.IntfIds)
244
245 // For global sharing, make sure to refresh both local and global resource manager instances' range
246
247 if ONUIDShared == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH {
248 globalPONRMgr.UpdateRanges(ponrmgr.ONU_ID_START_IDX, ONUIDStart, ponrmgr.ONU_ID_END_IDX, ONUIDEnd,
249 "", 0, nil)
250 ponRMgr.UpdateRanges(ponrmgr.ONU_ID_START_IDX, ONUIDStart, ponrmgr.ONU_ID_END_IDX, ONUIDEnd,
251 "", 0, globalPONRMgr)
252 }
253 if AllocIDShared == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH {
254 globalPONRMgr.UpdateRanges(ponrmgr.ALLOC_ID_START_IDX, AllocIDStart, ponrmgr.ALLOC_ID_END_IDX, AllocIDEnd,
255 "", 0, nil)
256
257 ponRMgr.UpdateRanges(ponrmgr.ALLOC_ID_START_IDX, AllocIDStart, ponrmgr.ALLOC_ID_END_IDX, AllocIDEnd,
258 "", 0, globalPONRMgr)
259 }
260 if GEMPortIDShared == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH {
261 globalPONRMgr.UpdateRanges(ponrmgr.GEMPORT_ID_START_IDX, GEMPortIDStart, ponrmgr.GEMPORT_ID_END_IDX, GEMPortIDEnd,
262 "", 0, nil)
263 ponRMgr.UpdateRanges(ponrmgr.GEMPORT_ID_START_IDX, GEMPortIDStart, ponrmgr.GEMPORT_ID_END_IDX, GEMPortIDEnd,
264 "", 0, globalPONRMgr)
265 }
266 if FlowIDShared == openolt.DeviceInfo_DeviceResourceRanges_Pool_SHARED_BY_ALL_INTF_ALL_TECH {
267 globalPONRMgr.UpdateRanges(ponrmgr.FLOW_ID_START_IDX, FlowIDStart, ponrmgr.FLOW_ID_END_IDX, FlowIDEnd,
268 "", 0, nil)
269 ponRMgr.UpdateRanges(ponrmgr.FLOW_ID_START_IDX, FlowIDStart, ponrmgr.FLOW_ID_END_IDX, FlowIDEnd,
270 "", 0, globalPONRMgr)
271 }
272
273 // Make sure loaded range fits the platform bit encoding ranges
274 ponRMgr.UpdateRanges(ponrmgr.UNI_ID_START_IDX, 0, ponrmgr.UNI_ID_END_IDX /* TODO =OpenOltPlatform.MAX_UNIS_PER_ONU-1*/, 1, "", 0, nil)
275}
276
277// Delete clears used resources for the particular olt device being deleted
278func (RsrcMgr *OpenOltResourceMgr) Delete() error {
279 /* TODO
280 def __del__(self):
281 self.log.info("clearing-device-resource-pool")
282 for key, resource_mgr in self.resource_mgrs.iteritems():
283 resource_mgr.clear_device_resource_pool()
284
285 def assert_pon_id_limit(self, pon_intf_id):
286 assert pon_intf_id in self.resource_mgrs
287
288 def assert_onu_id_limit(self, pon_intf_id, onu_id):
289 self.assert_pon_id_limit(pon_intf_id)
290 self.resource_mgrs[pon_intf_id].assert_resource_limits(onu_id, PONResourceManager.ONU_ID)
291
292 @property
293 def max_uni_id_per_onu(self):
294 return 0 #OpenOltPlatform.MAX_UNIS_PER_ONU-1, zero-based indexing Uncomment or override to make default multi-uni
295
296 def assert_uni_id_limit(self, pon_intf_id, onu_id, uni_id):
297 self.assert_onu_id_limit(pon_intf_id, onu_id)
298 self.resource_mgrs[pon_intf_id].assert_resource_limits(uni_id, PONResourceManager.UNI_ID)
299 */
300 for _, rsrcMgr := range RsrcMgr.ResourceMgrs {
301 if err := rsrcMgr.ClearDeviceResourcePool(); err != nil {
302 log.Debug("Failed to clear device resource pool")
303 return err
304 }
305 }
306 log.Debug("Cleared device resource pool")
307 return nil
308}
309
310// GetONUID returns the available OnuID for the given pon-port
311func (RsrcMgr *OpenOltResourceMgr) GetONUID(ponIntfID uint32) (uint32, error) {
312 // Check if Pon Interface ID is present in Resource-manager-map
313 if _, ok := RsrcMgr.ResourceMgrs[ponIntfID]; !ok {
314 err := errors.New("invalid-pon-interface-" + strconv.Itoa(int(ponIntfID)))
315 return 0, err
316 }
317 // Get ONU id for a provided pon interface ID.
318 ONUID, err := RsrcMgr.ResourceMgrs[ponIntfID].GetResourceID(ponIntfID,
319 ponrmgr.ONU_ID, 1)
320 if err != nil {
321 log.Errorf("Failed to get resource for interface %d for type %s",
322 ponIntfID, ponrmgr.ONU_ID)
323 return 0, err
324 }
325 if ONUID != nil {
326 RsrcMgr.ResourceMgrs[ponIntfID].InitResourceMap(fmt.Sprintf("%d,%d", ponIntfID, ONUID[0]))
327 return ONUID[0], err
328 }
329
330 return 0, err // return OnuID 0 on error
331}
332
333// GetAllocID return the first Alloc ID for a given pon interface id and onu id and then update the resource map on
334// the KV store with the list of alloc_ids allocated for the pon_intf_onu_id tuple
335// Currently of all the alloc_ids available, it returns the first alloc_id in the list for tha given ONU
336func (RsrcMgr *OpenOltResourceMgr) GetAllocID(intfID uint32, onuID uint32, uniID uint32) uint32 {
337
338 var err error
339 IntfOnuIDUniID := fmt.Sprintf("%d,%d,%d", intfID, onuID, uniID)
340 AllocID := RsrcMgr.ResourceMgrs[intfID].GetCurrentAllocIDForOnu(IntfOnuIDUniID)
341 if AllocID != nil {
342 // Since we support only one alloc_id for the ONU at the moment,
343 // return the first alloc_id in the list, if available, for that
344 // ONU.
345 log.Debugw("Retrieved alloc ID from pon resource mgr", log.Fields{"AllocID": AllocID})
346 return AllocID[0]
347 }
348 AllocID, err = RsrcMgr.ResourceMgrs[intfID].GetResourceID(intfID,
349 ponrmgr.ALLOC_ID, 1)
350
351 if AllocID == nil || err != nil {
352 log.Error("Failed to allocate alloc id")
353 return 0
354 }
355 // update the resource map on KV store with the list of alloc_id
356 // allocated for the pon_intf_onu_id tuple
357 err = RsrcMgr.ResourceMgrs[intfID].UpdateAllocIdsForOnu(IntfOnuIDUniID, AllocID)
358 if err != nil {
359 log.Error("Failed to update Alloc ID")
360 return 0
361 }
362 log.Debugw("Allocated new Tcont from pon resource mgr", log.Fields{"AllocID": AllocID})
363 return AllocID[0]
364}
365
366// GetGEMPortID gets gem port id for a particular pon port, onu id and uni id and then update the resource map on
367// the KV store with the list of gemport_id allocated for the pon_intf_onu_id tuple
368func (RsrcMgr *OpenOltResourceMgr) GetGEMPortID(ponPort uint32, onuID uint32,
369 uniID uint32, NumOfPorts uint32) ([]uint32, error) {
370
371 /* Get gem port id for a particular pon port, onu id
372 and uni id.
373 */
374
375 var err error
376 IntfOnuIDUniID := fmt.Sprintf("%d,%d,%d", ponPort, onuID, uniID)
377
378 GEMPortList := RsrcMgr.ResourceMgrs[ponPort].GetCurrentGEMPortIDsForOnu(IntfOnuIDUniID)
379 if GEMPortList != nil {
380 return GEMPortList, nil
381 }
382
383 GEMPortList, err = RsrcMgr.ResourceMgrs[ponPort].GetResourceID(ponPort,
384 ponrmgr.GEMPORT_ID, NumOfPorts)
385 if err != nil && GEMPortList == nil {
386 log.Errorf("Failed to get gem port id for %s", IntfOnuIDUniID)
387 return nil, err
388 }
389
390 // update the resource map on KV store with the list of gemport_id
391 // allocated for the pon_intf_onu_id tuple
392 err = RsrcMgr.ResourceMgrs[ponPort].UpdateGEMPortIDsForOnu(IntfOnuIDUniID,
393 GEMPortList)
394 if err != nil {
395 log.Errorf("Failed to update GEM ports to kv store for %s", IntfOnuIDUniID)
396 return nil, err
397 }
398
399 return GEMPortList, err
400}
401
402// FreeFlowID returns the free flow id for a given interface, onu id and uni id
403func (RsrcMgr *OpenOltResourceMgr) FreeFlowID(IntfID uint32, onuID int32,
404 uniID int32, FlowID uint32) {
405 var IntfONUID string
406 var err error
407 FlowIds := make([]uint32, 0)
408
409 FlowIds = append(FlowIds, FlowID)
410 IntfONUID = fmt.Sprintf("%d,%d,%d", IntfID, onuID, uniID)
411 err = RsrcMgr.ResourceMgrs[IntfID].UpdateFlowIDForOnu(IntfONUID, FlowID, false)
412 if err != nil {
413 log.Errorw("Failed to Update flow id for", log.Fields{"intf": IntfONUID})
414 }
415 RsrcMgr.ResourceMgrs[IntfID].RemoveFlowIDInfo(IntfONUID, FlowID)
416 RsrcMgr.ResourceMgrs[IntfID].FreeResourceID(IntfID, ponrmgr.FLOW_ID, FlowIds)
417}
418
419// FreeFlowIDs releases the flow Ids
420func (RsrcMgr *OpenOltResourceMgr) FreeFlowIDs(IntfID uint32, onuID uint32,
421 uniID uint32, FlowID []uint32) {
422
423 RsrcMgr.ResourceMgrs[IntfID].FreeResourceID(IntfID, ponrmgr.FLOW_ID, FlowID)
424
425 var IntfOnuIDUniID string
426 var err error
427 for _, flow := range FlowID {
428 IntfOnuIDUniID = fmt.Sprintf("%d,%d,%d", IntfID, onuID, uniID)
429 err = RsrcMgr.ResourceMgrs[IntfID].UpdateFlowIDForOnu(IntfOnuIDUniID, flow, false)
430 if err != nil {
431 log.Errorw("Failed to Update flow id for", log.Fields{"intf": IntfOnuIDUniID})
432 }
433 RsrcMgr.ResourceMgrs[IntfID].RemoveFlowIDInfo(IntfOnuIDUniID, flow)
434 }
435}
436
437// FreeAllocID frees AllocID on the PON resource pool and also frees the allocID association
438// for the given OLT device.
439func (RsrcMgr *OpenOltResourceMgr) FreeAllocID(IntfID uint32, allocID uint32) {
440 allocIDs := make([]uint32, 0)
441 allocIDs = append(allocIDs, allocID)
442 RsrcMgr.ResourceMgrs[IntfID].FreeResourceID(IntfID, ponrmgr.ALLOC_ID, allocIDs)
443}
444
445// FreeGemPortID frees GemPortID on the PON resource pool and also frees the gemPortID association
446// for the given OLT device.
447func (RsrcMgr *OpenOltResourceMgr) FreeGemPortID(IntfID uint32, gemPortID uint32) {
448 gemPortIDs := make([]uint32, 0)
449 gemPortIDs = append(gemPortIDs, gemPortID)
450 RsrcMgr.ResourceMgrs[IntfID].FreeResourceID(IntfID, ponrmgr.GEMPORT_ID, gemPortIDs)
451}