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