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