blob: 4422a10116e2e09c64482ff2c853c714dd1514b9 [file] [log] [blame]
Scott Baker2c1c4822019-10-16 11:02:41 -07001/*
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
17package ponresourcemanager
18
19import (
20 "encoding/base64"
21 "encoding/json"
22 "errors"
23 "fmt"
24 "strconv"
25
26 bitmap "github.com/boljen/go-bitmap"
Scott Bakerce767002019-10-23 13:30:24 -070027 "github.com/opencord/voltha-lib-go/v2/pkg/db/kvstore"
28 "github.com/opencord/voltha-lib-go/v2/pkg/db/model"
29 "github.com/opencord/voltha-lib-go/v2/pkg/log"
30 tp "github.com/opencord/voltha-lib-go/v2/pkg/techprofile"
Scott Baker2c1c4822019-10-16 11:02:41 -070031)
32
33const (
34 //Constants to identify resource pool
35 UNI_ID = "UNI_ID"
36 ONU_ID = "ONU_ID"
37 ALLOC_ID = "ALLOC_ID"
38 GEMPORT_ID = "GEMPORT_ID"
39 FLOW_ID = "FLOW_ID"
40
41 //Constants for passing command line arugments
42 OLT_MODEL_ARG = "--olt_model"
43 PATH_PREFIX = "service/voltha/resource_manager/{%s}"
44 /*The resource ranges for a given device model should be placed
45 at 'resource_manager/<technology>/resource_ranges/<olt_model_type>'
46 path on the KV store.
47 If Resource Range parameters are to be read from the external KV store,
48 they are expected to be stored in the following format.
49 Note: All parameters are MANDATORY for now.
50 constants used as keys to reference the resource range parameters from
51 and external KV store.
52 */
53 UNI_ID_START_IDX = "uni_id_start"
54 UNI_ID_END_IDX = "uni_id_end"
55 ONU_ID_START_IDX = "onu_id_start"
56 ONU_ID_END_IDX = "onu_id_end"
57 ONU_ID_SHARED_IDX = "onu_id_shared"
58 ALLOC_ID_START_IDX = "alloc_id_start"
59 ALLOC_ID_END_IDX = "alloc_id_end"
60 ALLOC_ID_SHARED_IDX = "alloc_id_shared"
61 GEMPORT_ID_START_IDX = "gemport_id_start"
62 GEMPORT_ID_END_IDX = "gemport_id_end"
63 GEMPORT_ID_SHARED_IDX = "gemport_id_shared"
64 FLOW_ID_START_IDX = "flow_id_start"
65 FLOW_ID_END_IDX = "flow_id_end"
66 FLOW_ID_SHARED_IDX = "flow_id_shared"
67 NUM_OF_PON_PORT = "pon_ports"
68
69 /*
70 The KV store backend is initialized with a path prefix and we need to
71 provide only the suffix.
72 */
73 PON_RESOURCE_RANGE_CONFIG_PATH = "resource_ranges/%s"
74
75 //resource path suffix
76 //Path on the KV store for storing alloc id ranges and resource pool for a given interface
77 //Format: <device_id>/alloc_id_pool/<pon_intf_id>
78 ALLOC_ID_POOL_PATH = "{%s}/alloc_id_pool/{%d}"
79 //Path on the KV store for storing gemport id ranges and resource pool for a given interface
80 //Format: <device_id>/gemport_id_pool/<pon_intf_id>
81 GEMPORT_ID_POOL_PATH = "{%s}/gemport_id_pool/{%d}"
82 //Path on the KV store for storing onu id ranges and resource pool for a given interface
83 //Format: <device_id>/onu_id_pool/<pon_intf_id>
84 ONU_ID_POOL_PATH = "{%s}/onu_id_pool/{%d}"
85 //Path on the KV store for storing flow id ranges and resource pool for a given interface
86 //Format: <device_id>/flow_id_pool/<pon_intf_id>
87 FLOW_ID_POOL_PATH = "{%s}/flow_id_pool/{%d}"
88
89 //Path on the KV store for storing list of alloc IDs for a given ONU
90 //Format: <device_id>/<(pon_intf_id, onu_id)>/alloc_ids
91 ALLOC_ID_RESOURCE_MAP_PATH = "{%s}/{%s}/alloc_ids"
92
93 //Path on the KV store for storing list of gemport IDs for a given ONU
94 //Format: <device_id>/<(pon_intf_id, onu_id)>/gemport_ids
95 GEMPORT_ID_RESOURCE_MAP_PATH = "{%s}/{%s}/gemport_ids"
96
97 //Path on the KV store for storing list of Flow IDs for a given ONU
98 //Format: <device_id>/<(pon_intf_id, onu_id)>/flow_ids
99 FLOW_ID_RESOURCE_MAP_PATH = "{%s}/{%s}/flow_ids"
100
101 //Flow Id info: Use to store more metadata associated with the flow_id
102 //Format: <device_id>/<(pon_intf_id, onu_id)>/flow_id_info/<flow_id>
103 FLOW_ID_INFO_PATH = "{%s}/{%s}/flow_id_info/{%d}"
104
105 //Constants for internal usage.
106 PON_INTF_ID = "pon_intf_id"
107 START_IDX = "start_idx"
108 END_IDX = "end_idx"
109 POOL = "pool"
110 NUM_OF_PON_INTF = 16
111
112 KVSTORE_RETRY_TIMEOUT = 5
113)
114
115//type ResourceTypeIndex string
116//type ResourceType string
117
118type PONResourceManager struct {
119 //Implements APIs to initialize/allocate/release alloc/gemport/onu IDs.
120 Technology string
121 DeviceType string
122 DeviceID string
123 Backend string // ETCD, or consul
124 Host string // host ip of the KV store
125 Port int // port number for the KV store
126 OLTModel string
127 KVStore *model.Backend
128 TechProfileMgr tp.TechProfileIf // create object of *tp.TechProfileMgr
129
130 // Below attribute, pon_resource_ranges, should be initialized
131 // by reading from KV store.
132 PonResourceRanges map[string]interface{}
133 SharedResourceMgrs map[string]*PONResourceManager
134 SharedIdxByType map[string]string
135 IntfIDs []uint32 // list of pon interface IDs
136 Globalorlocal string
137}
138
139func newKVClient(storeType string, address string, timeout int) (kvstore.Client, error) {
140 log.Infow("kv-store-type", log.Fields{"store": storeType})
141 switch storeType {
142 case "consul":
143 return kvstore.NewConsulClient(address, timeout)
144 case "etcd":
145 return kvstore.NewEtcdClient(address, timeout)
146 }
147 return nil, errors.New("unsupported-kv-store")
148}
149
150func SetKVClient(Technology string, Backend string, Host string, Port int) *model.Backend {
151 addr := Host + ":" + strconv.Itoa(Port)
152 // TODO : Make sure direct call to NewBackend is working fine with backend , currently there is some
153 // issue between kv store and backend , core is not calling NewBackend directly
154 kvClient, err := newKVClient(Backend, addr, KVSTORE_RETRY_TIMEOUT)
155 if err != nil {
156 log.Fatalw("Failed to init KV client\n", log.Fields{"err": err})
157 return nil
158 }
159 kvbackend := &model.Backend{
160 Client: kvClient,
161 StoreType: Backend,
162 Host: Host,
163 Port: Port,
164 Timeout: KVSTORE_RETRY_TIMEOUT,
165 PathPrefix: fmt.Sprintf(PATH_PREFIX, Technology)}
166
167 return kvbackend
168}
169
170// NewPONResourceManager creates a new PON resource manager.
171func NewPONResourceManager(Technology string, DeviceType string, DeviceID string, Backend string, Host string, Port int) (*PONResourceManager, error) {
172 var PONMgr PONResourceManager
173 PONMgr.Technology = Technology
174 PONMgr.DeviceType = DeviceType
175 PONMgr.DeviceID = DeviceID
176 PONMgr.Backend = Backend
177 PONMgr.Host = Host
178 PONMgr.Port = Port
179 PONMgr.KVStore = SetKVClient(Technology, Backend, Host, Port)
180 if PONMgr.KVStore == nil {
181 log.Error("KV Client initilization failed")
182 return nil, errors.New("Failed to init KV client")
183 }
184 // Initialize techprofile for this technology
185 if PONMgr.TechProfileMgr, _ = tp.NewTechProfile(&PONMgr, Backend, Host, Port); PONMgr.TechProfileMgr == nil {
186 log.Error("Techprofile initialization failed")
187 return nil, errors.New("Failed to init tech profile")
188 }
189 PONMgr.PonResourceRanges = make(map[string]interface{})
190 PONMgr.SharedResourceMgrs = make(map[string]*PONResourceManager)
191 PONMgr.SharedIdxByType = make(map[string]string)
192 PONMgr.SharedIdxByType[ONU_ID] = ONU_ID_SHARED_IDX
193 PONMgr.SharedIdxByType[ALLOC_ID] = ALLOC_ID_SHARED_IDX
194 PONMgr.SharedIdxByType[GEMPORT_ID] = GEMPORT_ID_SHARED_IDX
195 PONMgr.SharedIdxByType[FLOW_ID] = FLOW_ID_SHARED_IDX
196 PONMgr.IntfIDs = make([]uint32, NUM_OF_PON_INTF)
197 PONMgr.OLTModel = DeviceType
198 return &PONMgr, nil
199}
200
201/*
202 Initialize PON resource ranges with config fetched from kv store.
203 return boolean: True if PON resource ranges initialized else false
204 Try to initialize the PON Resource Ranges from KV store based on the
205 OLT model key, if available
206*/
207
208func (PONRMgr *PONResourceManager) InitResourceRangesFromKVStore() bool {
209 //Initialize PON resource ranges with config fetched from kv store.
210 //:return boolean: True if PON resource ranges initialized else false
211 // Try to initialize the PON Resource Ranges from KV store based on the
212 // OLT model key, if available
213 if PONRMgr.OLTModel == "" {
214 log.Error("Failed to get OLT model")
215 return false
216 }
217 Path := fmt.Sprintf(PON_RESOURCE_RANGE_CONFIG_PATH, PONRMgr.OLTModel)
218 //get resource from kv store
219 Result, err := PONRMgr.KVStore.Get(Path)
220 if err != nil {
221 log.Debugf("Error in fetching resource %s from KV strore", Path)
222 return false
223 }
224 if Result == nil {
225 log.Debug("There may be no resources in the KV store in case of fresh bootup, return true")
226 return false
227 }
228 //update internal ranges from kv ranges. If there are missing
229 // values in the KV profile, continue to use the defaults
230 Value, err := ToByte(Result.Value)
231 if err != nil {
232 log.Error("Failed to convert kvpair to byte string")
233 return false
234 }
235 if err := json.Unmarshal(Value, &PONRMgr.PonResourceRanges); err != nil {
236 log.Error("Failed to Unmarshal json byte")
237 return false
238 }
239 log.Debug("Init resource ranges from kvstore success")
240 return true
241}
242
243func (PONRMgr *PONResourceManager) UpdateRanges(StartIDx string, StartID uint32, EndIDx string, EndID uint32,
244 SharedIDx string, SharedPoolID uint32, RMgr *PONResourceManager) {
245 /*
246 Update the ranges for all reosurce type in the intermnal maps
247 param: resource type start index
248 param: start ID
249 param: resource type end index
250 param: end ID
251 param: resource type shared index
252 param: shared pool id
253 param: global resource manager
254 */
255 log.Debugf("update ranges for %s, %d", StartIDx, StartID)
256
257 if StartID != 0 {
258 if (PONRMgr.PonResourceRanges[StartIDx] == nil) || (PONRMgr.PonResourceRanges[StartIDx].(uint32) < StartID) {
259 PONRMgr.PonResourceRanges[StartIDx] = StartID
260 }
261 }
262 if EndID != 0 {
263 if (PONRMgr.PonResourceRanges[EndIDx] == nil) || (PONRMgr.PonResourceRanges[EndIDx].(uint32) > EndID) {
264 PONRMgr.PonResourceRanges[EndIDx] = EndID
265 }
266 }
267 //if SharedPoolID != 0 {
268 PONRMgr.PonResourceRanges[SharedIDx] = SharedPoolID
269 //}
270 if RMgr != nil {
271 PONRMgr.SharedResourceMgrs[SharedIDx] = RMgr
272 }
273}
274
275func (PONRMgr *PONResourceManager) InitDefaultPONResourceRanges(ONUIDStart uint32,
276 ONUIDEnd uint32,
277 ONUIDSharedPoolID uint32,
278 AllocIDStart uint32,
279 AllocIDEnd uint32,
280 AllocIDSharedPoolID uint32,
281 GEMPortIDStart uint32,
282 GEMPortIDEnd uint32,
283 GEMPortIDSharedPoolID uint32,
284 FlowIDStart uint32,
285 FlowIDEnd uint32,
286 FlowIDSharedPoolID uint32,
287 UNIIDStart uint32,
288 UNIIDEnd uint32,
289 NoOfPONPorts uint32,
290 IntfIDs []uint32) bool {
291
292 /*Initialize default PON resource ranges
293
294 :param onu_id_start_idx: onu id start index
295 :param onu_id_end_idx: onu id end index
296 :param onu_id_shared_pool_id: pool idx for id shared by all intfs or None for no sharing
297 :param alloc_id_start_idx: alloc id start index
298 :param alloc_id_end_idx: alloc id end index
299 :param alloc_id_shared_pool_id: pool idx for alloc id shared by all intfs or None for no sharing
300 :param gemport_id_start_idx: gemport id start index
301 :param gemport_id_end_idx: gemport id end index
302 :param gemport_id_shared_pool_id: pool idx for gemport id shared by all intfs or None for no sharing
303 :param flow_id_start_idx: flow id start index
304 :param flow_id_end_idx: flow id end index
305 :param flow_id_shared_pool_id: pool idx for flow id shared by all intfs or None for no sharing
306 :param num_of_pon_ports: number of PON ports
307 :param intf_ids: interfaces serviced by this manager
308 */
309 PONRMgr.UpdateRanges(ONU_ID_START_IDX, ONUIDStart, ONU_ID_END_IDX, ONUIDEnd, ONU_ID_SHARED_IDX, ONUIDSharedPoolID, nil)
310 PONRMgr.UpdateRanges(ALLOC_ID_START_IDX, AllocIDStart, ALLOC_ID_END_IDX, AllocIDEnd, ALLOC_ID_SHARED_IDX, AllocIDSharedPoolID, nil)
311 PONRMgr.UpdateRanges(GEMPORT_ID_START_IDX, GEMPortIDStart, GEMPORT_ID_END_IDX, GEMPortIDEnd, GEMPORT_ID_SHARED_IDX, GEMPortIDSharedPoolID, nil)
312 PONRMgr.UpdateRanges(FLOW_ID_START_IDX, FlowIDStart, FLOW_ID_END_IDX, FlowIDEnd, FLOW_ID_SHARED_IDX, FlowIDSharedPoolID, nil)
313 PONRMgr.UpdateRanges(UNI_ID_START_IDX, UNIIDStart, UNI_ID_END_IDX, UNIIDEnd, "", 0, nil)
314 log.Debug("Initialize default range values")
315 var i uint32
316 if IntfIDs == nil {
317 for i = 0; i < NoOfPONPorts; i++ {
318 PONRMgr.IntfIDs = append(PONRMgr.IntfIDs, i)
319 }
320 } else {
321 PONRMgr.IntfIDs = IntfIDs
322 }
323 return true
324}
325
326func (PONRMgr *PONResourceManager) InitDeviceResourcePool() error {
327
328 //Initialize resource pool for all PON ports.
329
330 log.Debug("Init resource ranges")
331
332 var err error
333 for _, Intf := range PONRMgr.IntfIDs {
334 SharedPoolID := PONRMgr.PonResourceRanges[ONU_ID_SHARED_IDX].(uint32)
335 if SharedPoolID != 0 {
336 Intf = SharedPoolID
337 }
338 if err = PONRMgr.InitResourceIDPool(Intf, ONU_ID,
339 PONRMgr.PonResourceRanges[ONU_ID_START_IDX].(uint32),
340 PONRMgr.PonResourceRanges[ONU_ID_END_IDX].(uint32)); err != nil {
341 log.Error("Failed to init ONU ID resource pool")
342 return err
343 }
344 if SharedPoolID != 0 {
345 break
346 }
347 }
348
349 for _, Intf := range PONRMgr.IntfIDs {
350 SharedPoolID := PONRMgr.PonResourceRanges[ALLOC_ID_SHARED_IDX].(uint32)
351 if SharedPoolID != 0 {
352 Intf = SharedPoolID
353 }
354 if err = PONRMgr.InitResourceIDPool(Intf, ALLOC_ID,
355 PONRMgr.PonResourceRanges[ALLOC_ID_START_IDX].(uint32),
356 PONRMgr.PonResourceRanges[ALLOC_ID_END_IDX].(uint32)); err != nil {
357 log.Error("Failed to init ALLOC ID resource pool ")
358 return err
359 }
360 if SharedPoolID != 0 {
361 break
362 }
363 }
364 for _, Intf := range PONRMgr.IntfIDs {
365 SharedPoolID := PONRMgr.PonResourceRanges[GEMPORT_ID_SHARED_IDX].(uint32)
366 if SharedPoolID != 0 {
367 Intf = SharedPoolID
368 }
369 if err = PONRMgr.InitResourceIDPool(Intf, GEMPORT_ID,
370 PONRMgr.PonResourceRanges[GEMPORT_ID_START_IDX].(uint32),
371 PONRMgr.PonResourceRanges[GEMPORT_ID_END_IDX].(uint32)); err != nil {
372 log.Error("Failed to init GEMPORT ID resource pool")
373 return err
374 }
375 if SharedPoolID != 0 {
376 break
377 }
378 }
379
380 for _, Intf := range PONRMgr.IntfIDs {
381 SharedPoolID := PONRMgr.PonResourceRanges[FLOW_ID_SHARED_IDX].(uint32)
382 if SharedPoolID != 0 {
383 Intf = SharedPoolID
384 }
385 if err = PONRMgr.InitResourceIDPool(Intf, FLOW_ID,
386 PONRMgr.PonResourceRanges[FLOW_ID_START_IDX].(uint32),
387 PONRMgr.PonResourceRanges[FLOW_ID_END_IDX].(uint32)); err != nil {
388 log.Error("Failed to init FLOW ID resource pool")
389 return err
390 }
391 if SharedPoolID != 0 {
392 break
393 }
394 }
395 return err
396}
397
398func (PONRMgr *PONResourceManager) ClearDeviceResourcePool() error {
399
400 //Clear resource pool for all PON ports.
401
402 log.Debug("Clear resource ranges")
403
404 for _, Intf := range PONRMgr.IntfIDs {
405 SharedPoolID := PONRMgr.PonResourceRanges[ONU_ID_SHARED_IDX].(uint32)
406 if SharedPoolID != 0 {
407 Intf = SharedPoolID
408 }
409 if status := PONRMgr.ClearResourceIDPool(Intf, ONU_ID); status != true {
410 log.Error("Failed to clear ONU ID resource pool")
411 return errors.New("Failed to clear ONU ID resource pool")
412 }
413 if SharedPoolID != 0 {
414 break
415 }
416 }
417
418 for _, Intf := range PONRMgr.IntfIDs {
419 SharedPoolID := PONRMgr.PonResourceRanges[ALLOC_ID_SHARED_IDX].(uint32)
420 if SharedPoolID != 0 {
421 Intf = SharedPoolID
422 }
423 if status := PONRMgr.ClearResourceIDPool(Intf, ALLOC_ID); status != true {
424 log.Error("Failed to clear ALLOC ID resource pool ")
425 return errors.New("Failed to clear ALLOC ID resource pool")
426 }
427 if SharedPoolID != 0 {
428 break
429 }
430 }
431 for _, Intf := range PONRMgr.IntfIDs {
432 SharedPoolID := PONRMgr.PonResourceRanges[GEMPORT_ID_SHARED_IDX].(uint32)
433 if SharedPoolID != 0 {
434 Intf = SharedPoolID
435 }
436 if status := PONRMgr.ClearResourceIDPool(Intf, GEMPORT_ID); status != true {
437 log.Error("Failed to clear GEMPORT ID resource pool")
438 return errors.New("Failed to clear GEMPORT ID resource pool")
439 }
440 if SharedPoolID != 0 {
441 break
442 }
443 }
444
445 for _, Intf := range PONRMgr.IntfIDs {
446 SharedPoolID := PONRMgr.PonResourceRanges[FLOW_ID_SHARED_IDX].(uint32)
447 if SharedPoolID != 0 {
448 Intf = SharedPoolID
449 }
450 if status := PONRMgr.ClearResourceIDPool(Intf, FLOW_ID); status != true {
451 log.Error("Failed to clear FLOW ID resource pool")
452 return errors.New("Failed to clear FLOW ID resource pool")
453 }
454 if SharedPoolID != 0 {
455 break
456 }
457 }
458 return nil
459}
460
461func (PONRMgr *PONResourceManager) InitResourceIDPool(Intf uint32, ResourceType string, StartID uint32, EndID uint32) error {
462
463 /*Initialize Resource ID pool for a given Resource Type on a given PON Port
464
465 :param pon_intf_id: OLT PON interface id
466 :param resource_type: String to identify type of resource
467 :param start_idx: start index for onu id pool
468 :param end_idx: end index for onu id pool
469 :return boolean: True if resource id pool initialized else false
470 */
471
472 // delegate to the master instance if sharing enabled across instances
473 SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
474 if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
475 return SharedResourceMgr.InitResourceIDPool(Intf, ResourceType, StartID, EndID)
476 }
477
478 Path := PONRMgr.GetPath(Intf, ResourceType)
479 if Path == "" {
480 log.Errorf("Failed to get path for resource type %s", ResourceType)
481 return errors.New(fmt.Sprintf("Failed to get path for resource type %s", ResourceType))
482 }
483
484 //In case of adapter reboot and reconciliation resource in kv store
485 //checked for its presence if not kv store update happens
486 Res, err := PONRMgr.GetResource(Path)
487 if (err == nil) && (Res != nil) {
488 log.Debugf("Resource %s already present in store ", Path)
489 return nil
490 } else {
491 FormatResult, err := PONRMgr.FormatResource(Intf, StartID, EndID)
492 if err != nil {
493 log.Errorf("Failed to format resource")
494 return err
495 }
496 // Add resource as json in kv store.
497 err = PONRMgr.KVStore.Put(Path, FormatResult)
498 if err == nil {
499 log.Debug("Successfuly posted to kv store")
500 return err
501 }
502 }
503
504 log.Debug("Error initializing pool")
505
506 return err
507}
508
509func (PONRMgr *PONResourceManager) FormatResource(IntfID uint32, StartIDx uint32, EndIDx uint32) ([]byte, error) {
510 /*
511 Format resource as json.
512 :param pon_intf_id: OLT PON interface id
513 :param start_idx: start index for id pool
514 :param end_idx: end index for id pool
515 :return dictionary: resource formatted as map
516 */
517 // Format resource as json to be stored in backend store
518 Resource := make(map[string]interface{})
519 Resource[PON_INTF_ID] = IntfID
520 Resource[START_IDX] = StartIDx
521 Resource[END_IDX] = EndIDx
522 /*
523 Resource pool stored in backend store as binary string.
524 Tracking the resource allocation will be done by setting the bits \
525 in the byte array. The index set will be the resource number allocated.
526 */
527 var TSData *bitmap.Threadsafe
528 if TSData = bitmap.NewTS(int(EndIDx)); TSData == nil {
529 log.Error("Failed to create a bitmap")
530 return nil, errors.New("Failed to create bitmap")
531 }
532 Resource[POOL] = TSData.Data(false) //we pass false so as the TSData lib api does not do a copy of the data and return
533
534 Value, err := json.Marshal(Resource)
535 if err != nil {
536 log.Errorf("Failed to marshall resource")
537 return nil, err
538 }
539 return Value, err
540}
541func (PONRMgr *PONResourceManager) GetResource(Path string) (map[string]interface{}, error) {
542 /*
543 Get resource from kv store.
544
545 :param path: path to get resource
546 :return: resource if resource present in kv store else None
547 */
548 //get resource from kv store
549
550 var Value []byte
551 Result := make(map[string]interface{})
552 var Str string
553
554 Resource, err := PONRMgr.KVStore.Get(Path)
555 if (err != nil) || (Resource == nil) {
556 log.Debugf("Resource unavailable at %s", Path)
557 return nil, err
558 }
559
560 Value, err = ToByte(Resource.Value)
561
562 // decode resource fetched from backend store to dictionary
563 err = json.Unmarshal(Value, &Result)
564 if err != nil {
565 log.Error("Failed to decode resource")
566 return Result, err
567 }
568 /*
569 resource pool in backend store stored as binary string whereas to
570 access the pool to generate/release IDs it need to be converted
571 as BitArray
572 */
573 Str, err = ToString(Result[POOL])
574 if err != nil {
575 log.Error("Failed to conver to kv pair to string")
576 return Result, err
577 }
578 Decode64, _ := base64.StdEncoding.DecodeString(Str)
579 Result[POOL], err = ToByte(Decode64)
580 if err != nil {
581 log.Error("Failed to convert resource pool to byte")
582 return Result, err
583 }
584
585 return Result, err
586}
587
588func (PONRMgr *PONResourceManager) GetPath(IntfID uint32, ResourceType string) string {
589 /*
590 Get path for given resource type.
591 :param pon_intf_id: OLT PON interface id
592 :param resource_type: String to identify type of resource
593 :return: path for given resource type
594 */
595
596 /*
597 Get the shared pool for the given resource type.
598 all the resource ranges and the shared resource maps are initialized during the init.
599 */
600 SharedPoolID := PONRMgr.PonResourceRanges[PONRMgr.SharedIdxByType[ResourceType]].(uint32)
601 if SharedPoolID != 0 {
602 IntfID = SharedPoolID
603 }
604 var Path string
605 if ResourceType == ONU_ID {
606 Path = fmt.Sprintf(ONU_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
607 } else if ResourceType == ALLOC_ID {
608 Path = fmt.Sprintf(ALLOC_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
609 } else if ResourceType == GEMPORT_ID {
610 Path = fmt.Sprintf(GEMPORT_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
611 } else if ResourceType == FLOW_ID {
612 Path = fmt.Sprintf(FLOW_ID_POOL_PATH, PONRMgr.DeviceID, IntfID)
613 } else {
614 log.Error("Invalid resource pool identifier")
615 }
616 return Path
617}
618
619func (PONRMgr *PONResourceManager) GetResourceID(IntfID uint32, ResourceType string, NumIDs uint32) ([]uint32, error) {
620 /*
621 Create alloc/gemport/onu/flow id for given OLT PON interface.
622 :param pon_intf_id: OLT PON interface id
623 :param resource_type: String to identify type of resource
624 :param num_of_id: required number of ids
625 :return list/uint32/None: list, uint32 or None if resource type is
626 alloc_id/gemport_id, onu_id or invalid type respectively
627 */
628 if NumIDs < 1 {
629 log.Error("Invalid number of resources requested")
630 return nil, errors.New(fmt.Sprintf("Invalid number of resources requested %d", NumIDs))
631 }
632 // delegate to the master instance if sharing enabled across instances
633
634 SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
635 if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
636 return SharedResourceMgr.GetResourceID(IntfID, ResourceType, NumIDs)
637 }
638 log.Debugf("Fetching resource from %s rsrc mgr for resource %s", PONRMgr.Globalorlocal, ResourceType)
639
640 Path := PONRMgr.GetPath(IntfID, ResourceType)
641 if Path == "" {
642 log.Errorf("Failed to get path for resource type %s", ResourceType)
643 return nil, errors.New(fmt.Sprintf("Failed to get path for resource type %s", ResourceType))
644 }
645 log.Debugf("Get resource for type %s on path %s", ResourceType, Path)
646 var Result []uint32
647 var NextID uint32
648 Resource, err := PONRMgr.GetResource(Path)
649 if (err == nil) && (ResourceType == ONU_ID) || (ResourceType == FLOW_ID) {
650 if NextID, err = PONRMgr.GenerateNextID(Resource); err != nil {
651 log.Error("Failed to Generate ID")
652 return Result, err
653 }
654 Result = append(Result, NextID)
655 } else if (err == nil) && ((ResourceType == GEMPORT_ID) || (ResourceType == ALLOC_ID)) {
656 if NumIDs == 1 {
657 if NextID, err = PONRMgr.GenerateNextID(Resource); err != nil {
658 log.Error("Failed to Generate ID")
659 return Result, err
660 }
661 Result = append(Result, NextID)
662 } else {
663 for NumIDs > 0 {
664 if NextID, err = PONRMgr.GenerateNextID(Resource); err != nil {
665 log.Error("Failed to Generate ID")
666 return Result, err
667 }
668 Result = append(Result, NextID)
669 NumIDs--
670 }
671 }
672 } else {
673 log.Error("get resource failed")
674 return Result, err
675 }
676
677 //Update resource in kv store
678 if PONRMgr.UpdateResource(Path, Resource) != nil {
679 log.Errorf("Failed to update resource %s", Path)
680 return nil, errors.New(fmt.Sprintf("Failed to update resource %s", Path))
681 }
682 return Result, nil
683}
684
685func checkValidResourceType(ResourceType string) bool {
686 KnownResourceTypes := []string{ONU_ID, ALLOC_ID, GEMPORT_ID, FLOW_ID}
687
688 for _, v := range KnownResourceTypes {
689 if v == ResourceType {
690 return true
691 }
692 }
693 return false
694}
695
696func (PONRMgr *PONResourceManager) FreeResourceID(IntfID uint32, ResourceType string, ReleaseContent []uint32) bool {
697 /*
698 Release alloc/gemport/onu/flow id for given OLT PON interface.
699 :param pon_intf_id: OLT PON interface id
700 :param resource_type: String to identify type of resource
701 :param release_content: required number of ids
702 :return boolean: True if all IDs in given release_content release else False
703 */
704 if checkValidResourceType(ResourceType) == false {
705 log.Error("Invalid resource type")
706 return false
707 }
708 if ReleaseContent == nil {
709 log.Debug("Nothing to release")
710 return true
711 }
712 // delegate to the master instance if sharing enabled across instances
713 SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
714 if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
715 return SharedResourceMgr.FreeResourceID(IntfID, ResourceType, ReleaseContent)
716 }
717 Path := PONRMgr.GetPath(IntfID, ResourceType)
718 if Path == "" {
719 log.Error("Failed to get path")
720 return false
721 }
722 Resource, err := PONRMgr.GetResource(Path)
723 if err != nil {
724 log.Error("Failed to get resource")
725 return false
726 }
727 for _, Val := range ReleaseContent {
728 PONRMgr.ReleaseID(Resource, Val)
729 }
730 if PONRMgr.UpdateResource(Path, Resource) != nil {
731 log.Errorf("Free resource for %s failed", Path)
732 return false
733 }
734 return true
735}
736
737func (PONRMgr *PONResourceManager) UpdateResource(Path string, Resource map[string]interface{}) error {
738 /*
739 Update resource in resource kv store.
740 :param path: path to update resource
741 :param resource: resource need to be updated
742 :return boolean: True if resource updated in kv store else False
743 */
744 // TODO resource[POOL] = resource[POOL].bin
745 Value, err := json.Marshal(Resource)
746 if err != nil {
747 log.Error("failed to Marshal")
748 return err
749 }
750 err = PONRMgr.KVStore.Put(Path, Value)
751 if err != nil {
752 log.Error("failed to put data to kv store %s", Path)
753 return err
754 }
755 return nil
756}
757
758func (PONRMgr *PONResourceManager) ClearResourceIDPool(IntfID uint32, ResourceType string) bool {
759 /*
760 Clear Resource Pool for a given Resource Type on a given PON Port.
761 :return boolean: True if removed else False
762 */
763
764 // delegate to the master instance if sharing enabled across instances
765 SharedResourceMgr := PONRMgr.SharedResourceMgrs[PONRMgr.SharedIdxByType[ResourceType]]
766 if SharedResourceMgr != nil && PONRMgr != SharedResourceMgr {
767 return SharedResourceMgr.ClearResourceIDPool(IntfID, ResourceType)
768 }
769 Path := PONRMgr.GetPath(IntfID, ResourceType)
770 if Path == "" {
771 log.Error("Failed to get path")
772 return false
773 }
774
775 if err := PONRMgr.KVStore.Delete(Path); err != nil {
776 log.Errorf("Failed to delete resource %s", Path)
777 return false
778 }
779 log.Debugf("Cleared resource %s", Path)
780 return true
781}
782
783func (PONRMgr PONResourceManager) InitResourceMap(PONIntfONUID string) {
784 /*
785 Initialize resource map
786 :param pon_intf_onu_id: reference of PON interface id and onu id
787 */
788 // initialize pon_intf_onu_id tuple to alloc_ids map
789 AllocIDPath := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
790 var AllocIDs []byte
791 Result := PONRMgr.KVStore.Put(AllocIDPath, AllocIDs)
792 if Result != nil {
793 log.Error("Failed to update the KV store")
794 return
795 }
796 // initialize pon_intf_onu_id tuple to gemport_ids map
797 GEMPortIDPath := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
798 var GEMPortIDs []byte
799 Result = PONRMgr.KVStore.Put(GEMPortIDPath, GEMPortIDs)
800 if Result != nil {
801 log.Error("Failed to update the KV store")
802 return
803 }
804}
805
806func (PONRMgr PONResourceManager) RemoveResourceMap(PONIntfONUID string) bool {
807 /*
808 Remove resource map
809 :param pon_intf_onu_id: reference of PON interface id and onu id
810 */
811 // remove pon_intf_onu_id tuple to alloc_ids map
812 var err error
813 AllocIDPath := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
814 if err = PONRMgr.KVStore.Delete(AllocIDPath); err != nil {
815 log.Errorf("Failed to remove resource %s", AllocIDPath)
816 return false
817 }
818 // remove pon_intf_onu_id tuple to gemport_ids map
819 GEMPortIDPath := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
820 err = PONRMgr.KVStore.Delete(GEMPortIDPath)
821 if err != nil {
822 log.Errorf("Failed to remove resource %s", GEMPortIDPath)
823 return false
824 }
825
826 FlowIDPath := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, PONIntfONUID)
827 if FlowIDs, err := PONRMgr.KVStore.List(FlowIDPath); err != nil {
828 for _, Flow := range FlowIDs {
829 FlowIDInfoPath := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, PONIntfONUID, Flow.Value)
830 if err = PONRMgr.KVStore.Delete(FlowIDInfoPath); err != nil {
831 log.Errorf("Failed to remove resource %s", FlowIDInfoPath)
832 return false
833 }
834 }
835 }
836
837 if err = PONRMgr.KVStore.Delete(FlowIDPath); err != nil {
838 log.Errorf("Failed to remove resource %s", FlowIDPath)
839 return false
840 }
841
842 return true
843}
844
845func (PONRMgr *PONResourceManager) GetCurrentAllocIDForOnu(IntfONUID string) []uint32 {
846 /*
847 Get currently configured alloc ids for given pon_intf_onu_id
848 :param pon_intf_onu_id: reference of PON interface id and onu id
849 :return list: List of alloc_ids if available, else None
850 */
851 Path := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
852
853 var Data []uint32
854 Value, err := PONRMgr.KVStore.Get(Path)
855 if err == nil {
856 if Value != nil {
857 Val, err := ToByte(Value.Value)
858 if err != nil {
859 log.Errorw("Failed to convert into byte array", log.Fields{"error": err})
860 return Data
861 }
862 if err = json.Unmarshal(Val, &Data); err != nil {
863 log.Error("Failed to unmarshal", log.Fields{"error": err})
864 return Data
865 }
866 }
867 }
868 return Data
869}
870
871func (PONRMgr *PONResourceManager) GetCurrentGEMPortIDsForOnu(IntfONUID string) []uint32 {
872 /*
873 Get currently configured gemport ids for given pon_intf_onu_id
874 :param pon_intf_onu_id: reference of PON interface id and onu id
875 :return list: List of gemport IDs if available, else None
876 */
877
878 Path := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
879 log.Debugf("Getting current gemports for %s", Path)
880 var Data []uint32
881 Value, err := PONRMgr.KVStore.Get(Path)
882 if err == nil {
883 if Value != nil {
884 Val, _ := ToByte(Value.Value)
885 if err = json.Unmarshal(Val, &Data); err != nil {
886 log.Errorw("Failed to unmarshal", log.Fields{"error": err})
887 return Data
888 }
889 }
890 } else {
891 log.Errorf("Failed to get data from kvstore for %s", Path)
892 }
893 return Data
894}
895
896func (PONRMgr *PONResourceManager) GetCurrentFlowIDsForOnu(IntfONUID string) []uint32 {
897 /*
898 Get currently configured flow ids for given pon_intf_onu_id
899 :param pon_intf_onu_id: reference of PON interface id and onu id
900 :return list: List of Flow IDs if available, else None
901 */
902
903 Path := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
904
905 var Data []uint32
906 Value, err := PONRMgr.KVStore.Get(Path)
907 if err == nil {
908 if Value != nil {
909 Val, _ := ToByte(Value.Value)
910 if err = json.Unmarshal(Val, &Data); err != nil {
911 log.Error("Failed to unmarshal")
912 return Data
913 }
914 }
915 }
916 return Data
917}
918
919func (PONRMgr *PONResourceManager) GetFlowIDInfo(IntfONUID string, FlowID uint32, Data interface{}) error {
920 /*
921 Get flow details configured for the ONU.
922 :param pon_intf_onu_id: reference of PON interface id and onu id
923 :param flow_id: Flow Id reference
924 :param Data: Result
925 :return error: nil if no error in getting from KV store
926 */
927
928 Path := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, IntfONUID, FlowID)
929
930 Value, err := PONRMgr.KVStore.Get(Path)
931 if err == nil {
932 if Value != nil {
933 Val, err := ToByte(Value.Value)
934 if err != nil {
935 log.Errorw("Failed to convert flowinfo into byte array", log.Fields{"error": err})
936 return err
937 }
938 if err = json.Unmarshal(Val, Data); err != nil {
939 log.Errorw("Failed to unmarshal", log.Fields{"error": err})
940 return err
941 }
942 }
943 }
944 return err
945}
946
947func (PONRMgr *PONResourceManager) RemoveFlowIDInfo(IntfONUID string, FlowID uint32) bool {
948 /*
949 Get flow_id details configured for the ONU.
950 :param pon_intf_onu_id: reference of PON interface id and onu id
951 :param flow_id: Flow Id reference
952 */
953 Path := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, IntfONUID, FlowID)
954
955 if err := PONRMgr.KVStore.Delete(Path); err != nil {
956 log.Errorf("Falied to remove resource %s", Path)
957 return false
958 }
959 return true
960}
961
962func (PONRMgr *PONResourceManager) UpdateAllocIdsForOnu(IntfONUID string, AllocIDs []uint32) error {
963 /*
964 Update currently configured alloc ids for given pon_intf_onu_id
965 :param pon_intf_onu_id: reference of PON interface id and onu id
966 :param alloc_ids: list of alloc ids
967 */
968 var Value []byte
969 var err error
970 Path := fmt.Sprintf(ALLOC_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
971 Value, err = json.Marshal(AllocIDs)
972 if err != nil {
973 log.Error("failed to Marshal")
974 return err
975 }
976
977 if err = PONRMgr.KVStore.Put(Path, Value); err != nil {
978 log.Errorf("Failed to update resource %s", Path)
979 return err
980 }
981 return err
982}
983
984func (PONRMgr *PONResourceManager) UpdateGEMPortIDsForOnu(IntfONUID string, GEMPortIDs []uint32) error {
985 /*
986 Update currently configured gemport ids for given pon_intf_onu_id
987 :param pon_intf_onu_id: reference of PON interface id and onu id
988 :param gemport_ids: list of gem port ids
989 */
990
991 var Value []byte
992 var err error
993 Path := fmt.Sprintf(GEMPORT_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
994 log.Debugf("Updating gemport ids for %s", Path)
995 Value, err = json.Marshal(GEMPortIDs)
996 if err != nil {
997 log.Error("failed to Marshal")
998 return err
999 }
1000
1001 if err = PONRMgr.KVStore.Put(Path, Value); err != nil {
1002 log.Errorf("Failed to update resource %s", Path)
1003 return err
1004 }
1005 return err
1006}
1007
1008func checkForFlowIDInList(FlowIDList []uint32, FlowID uint32) (bool, uint32) {
1009 /*
1010 Check for a flow id in a given list of flow IDs.
1011 :param FLowIDList: List of Flow IDs
1012 :param FlowID: Flowd to check in the list
1013 : return true and the index if present false otherwise.
1014 */
1015
1016 for idx, _ := range FlowIDList {
1017 if FlowID == FlowIDList[idx] {
1018 return true, uint32(idx)
1019 }
1020 }
1021 return false, 0
1022}
1023
1024func (PONRMgr *PONResourceManager) UpdateFlowIDForOnu(IntfONUID string, FlowID uint32, Add bool) error {
1025 /*
1026 Update the flow_id list of the ONU (add or remove flow_id from the list)
1027 :param pon_intf_onu_id: reference of PON interface id and onu id
1028 :param flow_id: flow ID
1029 :param add: Boolean flag to indicate whether the flow_id should be
1030 added or removed from the list. Defaults to adding the flow.
1031 */
1032 var Value []byte
1033 var err error
1034 var RetVal bool
1035 var IDx uint32
1036 Path := fmt.Sprintf(FLOW_ID_RESOURCE_MAP_PATH, PONRMgr.DeviceID, IntfONUID)
1037 FlowIDs := PONRMgr.GetCurrentFlowIDsForOnu(IntfONUID)
1038
1039 if Add {
1040 if RetVal, IDx = checkForFlowIDInList(FlowIDs, FlowID); RetVal == true {
1041 return err
1042 }
1043 FlowIDs = append(FlowIDs, FlowID)
1044 } else {
1045 if RetVal, IDx = checkForFlowIDInList(FlowIDs, FlowID); RetVal == false {
1046 return err
1047 }
1048 // delete the index and shift
1049 FlowIDs = append(FlowIDs[:IDx], FlowIDs[IDx+1:]...)
1050 }
1051 Value, err = json.Marshal(FlowIDs)
1052 if err != nil {
1053 log.Error("Failed to Marshal")
1054 return err
1055 }
1056
1057 if err = PONRMgr.KVStore.Put(Path, Value); err != nil {
1058 log.Errorf("Failed to update resource %s", Path)
1059 return err
1060 }
1061 return err
1062}
1063
1064func (PONRMgr *PONResourceManager) UpdateFlowIDInfoForOnu(IntfONUID string, FlowID uint32, FlowData interface{}) error {
1065 /*
1066 Update any metadata associated with the flow_id. The flow_data could be json
1067 or any of other data structure. The resource manager doesnt care
1068 :param pon_intf_onu_id: reference of PON interface id and onu id
1069 :param flow_id: Flow ID
1070 :param flow_data: Flow data blob
1071 */
1072 var Value []byte
1073 var err error
1074 Path := fmt.Sprintf(FLOW_ID_INFO_PATH, PONRMgr.DeviceID, IntfONUID, FlowID)
1075 Value, err = json.Marshal(FlowData)
1076 if err != nil {
1077 log.Error("failed to Marshal")
1078 return err
1079 }
1080
1081 if err = PONRMgr.KVStore.Put(Path, Value); err != nil {
1082 log.Errorf("Failed to update resource %s", Path)
1083 return err
1084 }
1085 return err
1086}
1087
1088func (PONRMgr *PONResourceManager) GenerateNextID(Resource map[string]interface{}) (uint32, error) {
1089 /*
1090 Generate unique id having OFFSET as start
1091 :param resource: resource used to generate ID
1092 :return uint32: generated id
1093 */
1094 ByteArray, err := ToByte(Resource[POOL])
1095 if err != nil {
1096 log.Error("Failed to convert resource to byte array")
1097 return 0, err
1098 }
1099 Data := bitmap.TSFromData(ByteArray, false)
1100 if Data == nil {
1101 log.Error("Failed to get data from byte array")
1102 return 0, errors.New("Failed to get data from byte array")
1103 }
1104
1105 Len := Data.Len()
1106 var Idx int
1107 for Idx = 0; Idx < Len; Idx++ {
1108 Val := Data.Get(Idx)
1109 if Val == false {
1110 break
1111 }
1112 }
1113 Data.Set(Idx, true)
1114 res := uint32(Resource[START_IDX].(float64))
1115 Resource[POOL] = Data.Data(false)
1116 log.Debugf("Generated ID for %d", (uint32(Idx) + res))
1117 return (uint32(Idx) + res), err
1118}
1119
1120func (PONRMgr *PONResourceManager) ReleaseID(Resource map[string]interface{}, Id uint32) bool {
1121 /*
1122 Release unique id having OFFSET as start index.
1123 :param resource: resource used to release ID
1124 :param unique_id: id need to be released
1125 */
1126 ByteArray, err := ToByte(Resource[POOL])
1127 if err != nil {
1128 log.Error("Failed to convert resource to byte array")
1129 return false
1130 }
1131 Data := bitmap.TSFromData(ByteArray, false)
1132 if Data == nil {
1133 log.Error("Failed to get resource pool")
1134 return false
1135 }
1136 var Idx uint32
1137 Idx = Id - uint32(Resource[START_IDX].(float64))
1138 Data.Set(int(Idx), false)
1139 Resource[POOL] = Data.Data(false)
1140
1141 return true
1142}
1143
1144func (PONRMgr *PONResourceManager) GetTechnology() string {
1145 return PONRMgr.Technology
1146}
1147
1148func (PONRMgr *PONResourceManager) GetResourceTypeAllocID() string {
1149 return ALLOC_ID
1150}
1151
1152func (PONRMgr *PONResourceManager) GetResourceTypeGemPortID() string {
1153 return GEMPORT_ID
1154}
1155
1156// ToByte converts an interface value to a []byte. The interface should either be of
1157// a string type or []byte. Otherwise, an error is returned.
1158func ToByte(value interface{}) ([]byte, error) {
1159 switch t := value.(type) {
1160 case []byte:
1161 return value.([]byte), nil
1162 case string:
1163 return []byte(value.(string)), nil
1164 default:
1165 return nil, fmt.Errorf("unexpected-type-%T", t)
1166 }
1167}
1168
1169// ToString converts an interface value to a string. The interface should either be of
1170// a string type or []byte. Otherwise, an error is returned.
1171func ToString(value interface{}) (string, error) {
1172 switch t := value.(type) {
1173 case []byte:
1174 return string(value.([]byte)), nil
1175 case string:
1176 return value.(string), nil
1177 default:
1178 return "", fmt.Errorf("unexpected-type-%T", t)
1179 }
1180}