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