Skip to content

Commit

Permalink
feat(idpool): idpool feature for generating id's
Browse files Browse the repository at this point in the history
Signed-off-by: Venkatesh, Vemula <venkatesh.vemula@intel.com>
Signed-off-by: Atul Patel <Atul.Patel@intel.com>
Signed-off-by: Vemula Venkatesh <venkatesh.vemula@intel.com>
  • Loading branch information
venkyvsp committed Oct 15, 2024
1 parent 8f51de1 commit eb45583
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 30 deletions.
64 changes: 34 additions & 30 deletions pkg/LinuxGeneralModule/lgm.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ import (
// ModulelgmHandler enmpty interface
type ModulelgmHandler struct{}

// RoutingTableMax max value of routing table
const RoutingTableMax = 4000

// RoutingTableMin min value of routing table
const RoutingTableMin = 1000

// lgmComp string constant
const lgmComp string = "lgm"

Expand All @@ -46,10 +40,11 @@ const brStr string = "br-"
// vxlanStr string constant
const vxlanStr string = "vxlan-"

// GenerateRouteTable range specification, note that min <= max
func GenerateRouteTable() uint32 {
return uint32(rand.Intn(RoutingTableMax-RoutingTableMin+1) + RoutingTableMin) //nolint:gosec
}
// routingTableMax max value of routing table
const routingTableMax = 4000

// routingTableMin min value of routing table
const routingTableMin = 1000

// run runs the commands
func run(cmd []string, flag bool) (string, int) {
Expand Down Expand Up @@ -350,6 +345,9 @@ var ctx context.Context
// nlink variable wrapper
var nlink utils.Netlink

// RouteTableGen table id generate variable
var RouteTableGen utils.IDPool

// Initialize initializes the config, logger and subscribers
func Initialize() {
eb := eventbus.EBus
Expand All @@ -363,7 +361,8 @@ func Initialize() {
brTenant = "br-tenant"
ipMtu = config.GlobalConfig.LinuxFrr.IPMtu
ctx = context.Background()
nlink = utils.NewNetlinkWrapperWithArgs(config.GlobalConfig.Tracer)
RouteTableGen = utils.IDPoolInit("RTtable", routingTableMin, routingTableMax)
nlink = utils.NewNetlinkWrapperWithArgs(false)
// Set up the static configuration parts
_, err := nlink.LinkByName(ctx, brTenant)
if err != nil {
Expand Down Expand Up @@ -401,8 +400,8 @@ func setUpTenantBridge() {
}
}

// routingTableBusy checks if the route is in filterred list
func routingTableBusy(table uint32) (bool, error) {
// routingtableBusy checks if the route is in filterred list
func routingtableBusy(table uint32) (bool, error) {
routeList, err := nlink.RouteListFiltered(ctx, netlink.FAMILY_V4, &netlink.Route{Table: int(table)}, netlink.RT_FILTER_TABLE)
if err != nil {
return false, err
Expand Down Expand Up @@ -454,6 +453,7 @@ func setUpBridge(lb *infradb.LogicalBridge) bool {
//nolint:funlen,gocognit
func setUpVrf(vrf *infradb.Vrf) (string, bool) {
IPMtu := fmt.Sprintf("%+v", ipMtu)
var addKey int
if path.Base(vrf.Name) == "GRD" {
vrf.Metadata.RoutingTable = make([]*uint32, 2)
vrf.Metadata.RoutingTable[0] = new(uint32)
Expand All @@ -464,19 +464,23 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) {
}
vrf.Metadata.RoutingTable = make([]*uint32, 1)
vrf.Metadata.RoutingTable[0] = new(uint32)
var routingTable uint32
var routingtable uint32
name := vrf.Name
for {
routingTable = GenerateRouteTable()
isBusy, err := routingTableBusy(routingTable)
routingtable, _ = RouteTableGen.GetID(name, 0)
log.Printf("LGM assigned id %+v for vrf name %s\n", routingtable, vrf.Name)
isbusy, err := routingtableBusy(routingtable)
if err != nil {
log.Printf("LGM : Error occurred when checking if routing table %d is busy: %+v\n", routingTable, err)
log.Printf("LGM : Error occurred when checking if routing table %d is busy: %+v\n", routingtable, err)
return "", false
}
if !isBusy {
log.Printf("LGM: Routing Table %d is not busy\n", routingTable)
if !isbusy {
log.Printf("LGM: Routing Table %d is not busy\n", routingtable)
break
}
log.Printf("LGM: Routing Table %d is busy\n", routingTable)
log.Printf("LGM: Routing Table %d is busy\n", routingtable)
addKey++
name = fmt.Sprintf("%s%d", name, addKey)
}
var vtip string
if !reflect.ValueOf(vrf.Spec.VtepIP).IsZero() {
Expand All @@ -489,19 +493,19 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) {
return "", false
}
}
log.Printf("setUpVrf: %s %d\n", vtip, routingTable)
log.Printf("setUpVrf: %s %d\n", vtip, routingtable)
// Create the vrf interface for the specified routing table and add loopback address

linkAdderr := nlink.LinkAdd(ctx, &netlink.Vrf{
LinkAttrs: netlink.LinkAttrs{Name: path.Base(vrf.Name)},
Table: routingTable,
Table: routingtable,
})
if linkAdderr != nil {
log.Printf("LGM: Error in Adding vrf link table %d\n", routingTable)
log.Printf("LGM: Error in Adding vrf link table %d\n", routingtable)
return "", false
}

log.Printf("LGM: vrf link %s Added with table id %d\n", vrf.Name, routingTable)
log.Printf("LGM: vrf link %s Added with table id %d\n", vrf.Name, routingtable)

link, linkErr := nlink.LinkByName(ctx, path.Base(vrf.Name))
if linkErr != nil {
Expand Down Expand Up @@ -536,7 +540,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) {

Src1 := net.IPv4(0, 0, 0, 0)
route := netlink.Route{
Table: int(routingTable),
Table: int(routingtable),
Type: unix.RTN_THROW,
Protocol: 255,
Priority: 9999,
Expand All @@ -548,7 +552,7 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) {
return "", false
}

log.Printf("LGM : Added route throw default table %d proto opi_evpn_br metric 9999\n", routingTable)
log.Printf("LGM : Added route throw default table %d proto opi_evpn_br metric 9999\n", routingtable)
// Disable reverse-path filtering to accept ingress traffic punted by the pipeline
// disable_rp_filter("rep-"+vrf.Name)
// Configuration specific for VRFs associated with L3 EVPN
Expand Down Expand Up @@ -638,8 +642,8 @@ func setUpVrf(vrf *infradb.Vrf) (string, bool) {
return "", false
}
}
details := fmt.Sprintf("{\"routingTable\":\"%d\"}", routingTable)
*vrf.Metadata.RoutingTable[0] = routingTable
details := fmt.Sprintf("{\"routingtable\":\"%d\"}", routingtable)
*vrf.Metadata.RoutingTable[0] = routingtable
return details, true
}

Expand Down Expand Up @@ -775,7 +779,7 @@ func tearDownVrf(vrf *infradb.Vrf) bool {
if path.Base(vrf.Name) == "GRD" {
return true
}
routingTable := *vrf.Metadata.RoutingTable[0]
routingtable := *vrf.Metadata.RoutingTable[0]
// Delete the Linux networking artefacts in reverse order
if !reflect.ValueOf(vrf.Spec.Vni).IsZero() {
linkVxlan, linkErr := nlink.LinkByName(ctx, vxlanStr+path.Base(vrf.Name))
Expand All @@ -802,7 +806,7 @@ func tearDownVrf(vrf *infradb.Vrf) bool {
}
log.Printf("LGM : Delete br-%s\n", vrf.Name)
}
routeTable := fmt.Sprintf("%+v", routingTable)
routeTable := fmt.Sprintf("%+v", routingtable)
flusherr := nlink.RouteFlushTable(ctx, routeTable)
if flusherr != nil {
log.Printf("LGM: Error in flush table %+v\n", routeTable)
Expand Down
144 changes: 144 additions & 0 deletions pkg/utils/idpool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries.
// Copyright (C) 2023 Nordix Foundation.

// Package linuxgeneralmodule is the main package of the application

package utils

import (
"log"
"reflect"
)

// IDPool structure
/* Helper class for uniquely assigning IDs from a specified integer set (e.g. a
# range) to keys. IDs are assigned (or read) with GetID(key) and returned back
# into the pool with ReleaseID(key). The IDPool remembers a once-assigned ID
# for keys so that the same ID is assigned for a key. Only when the pool runs
# out of unassigned keys, it will recycle released ids and assign them to new
# keys.
# Optionally, the IDPool supports reference tracking for key/ID pairs. Clients
# can provide a unique reference when fetching and releasing an ID for a key
# to support multiple independent clients.
# The pool will only release the ID for the key, when the last client has the
# released the ID with its reference. When a reference is specified in GetID()
# and ReleaseID() the IDPool returns the current number of reference for the
# ID so that a caller knows when an ID was newly assigned (ref_count 1) or
# finally released (ref_count 0).
*/
type IDPool struct {
name string // Name of pool
_unusedids []uint32 // Yet unused IDs in pool Available ids
_idsinuse map[interface{}]uint32 // Mapping key: id for currently assigned ids
_idsforreuse map[interface{}]uint32 // Mapping key: id for previously assigned ids
_refs map[uint32][]interface{}
_size int // Size of the pool
}

// IDPoolInit initialize mod ptr pool
func IDPoolInit(name string, min uint32, max uint32) IDPool {
var pool IDPool
pool.name = name
pool._unusedids = make([]uint32, 0)
for j := min; j <= (max + 1); j++ {
pool._unusedids = append(pool._unusedids, j)
}
pool._size = len(pool._unusedids)
pool._idsinuse = make(map[interface{}]uint32)
pool._idsforreuse = make(map[interface{}]uint32)
pool._refs = make(map[uint32][]interface{})
return pool
}

func (ip *IDPool) _assignID(key interface{}) uint32 {
// Check if there was an id assigned for that key earlier
id := ip._idsforreuse[key]
if id != 0 {
// Re-use the old id
delete(ip._idsforreuse, key)
} else {
if len(ip._unusedids) != 0 {
// Pick an unused id
id = ip._unusedids[0]
ip._unusedids = ip._unusedids[1:len(ip._unusedids)]
} else {
if len(ip._idsforreuse) != 0 {
// Pick one of the ids earlier used for another key
for oldKey := range ip._idsforreuse {
delete(ip._idsforreuse, oldKey)
break
}
} else {
log.Printf("IDPool: Failed to allocate id for %+v. No free ids in pool.", key)
return 0
}
}
}
// Store the assigned id, if any
if id != 0 {
ip._idsinuse[key] = id
}
return id
}

// GetID get the mod ptr id from pool
func (ip *IDPool) GetID(key interface{}, ref interface{}) (uint32, uint32) {
id := ip._idsinuse[key]
if id == 0 {
id = ip._assignID(key)
if id == 0 {
return 0, 0
}
}
if ref != nil {
log.Printf("IDPool: GetID Assigning key : %+v , id %+v for ref %v", id, key, ref)
if reflect.ValueOf(ip._refs[id]).IsZero() {
ip._refs[id] = make([]interface{}, 0)
}
ip._refs[id] = append(ip._refs[id], ref)
return id, uint32(len(ip._refs[id]))
}
log.Printf("IDPool: GetID Assigning id %v for key %v and ref %v", id, key, ref)
return id, uint32(0)
}

func deleteRef(refSet []interface{}, ref interface{}) []interface{} {
var i uint32
for index, value := range refSet {
if value == ref {
i = uint32(index)
break
}
}
return append(refSet[:i], refSet[i+1:]...)
}

// ReleaseID get the reference id
func (ip *IDPool) ReleaseID(key interface{}, ref interface{}) (uint32, uint32) {
log.Printf("IDPool:ReleaseID Releasing id for key %v", key)
id := ip._idsinuse[key]
if ref == nil {
log.Printf("No id to release for key %v", key)
return 0, 0
}
refSet := ip._refs[id]
if !reflect.ValueOf(refSet).IsZero() && !reflect.ValueOf(ref).IsZero() {
refSet = deleteRef(refSet, ref)
}
if refSet != nil {
log.Printf("IDPool:ReleaseID Id %v has been released", id)
delete(ip._idsinuse, key)
if refSet != nil {
delete(ip._refs, id)
}
// Store released id for future reassignment
ip._idsforreuse[key] = id
} else {
log.Printf("IDPool:ReleaseID Keep id:%+v remaining references %+v", id, len(refSet))
}
if ref != nil {
return id, uint32(len(refSet))
}
return id, uint32(0)
}

0 comments on commit eb45583

Please sign in to comment.