From ec3a3187b1f54d3798c26dcebc5dec7ab83ae855 Mon Sep 17 00:00:00 2001 From: Khalid Nowaf Date: Mon, 1 Jul 2024 21:45:15 +0300 Subject: [PATCH 1/3] refactor(Trie): remove duplicated code --- pkg/trie/trie.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/pkg/trie/trie.go b/pkg/trie/trie.go index f76cdc8..d9a5e03 100644 --- a/pkg/trie/trie.go +++ b/pkg/trie/trie.go @@ -173,17 +173,10 @@ func (t *BinaryTrie[T]) ForEachChild(f func(t *BinaryTrie[T])) *BinaryTrie[T] { // if no conation is needed you can pass nil as while parameter // will return the original node t func (t *BinaryTrie[T]) ForEachStepDown(f func(t *BinaryTrie[T]), while func(t *BinaryTrie[T]) bool) *BinaryTrie[T] { - t.forEachStepDown(f, while) - return t -} - -// is a helper for ForEachStepDown to implement recursive traversal. -// will return the original node t -func (t *BinaryTrie[T]) forEachStepDown(f func(t *BinaryTrie[T]), while func(t *BinaryTrie[T]) bool) *BinaryTrie[T] { t.ForEachChild(func(child *BinaryTrie[T]) { if while == nil || while(t) { f(child) - child.forEachStepDown(f, while) + child.ForEachStepDown(f, while) } }) return t @@ -239,7 +232,7 @@ func (root *BinaryTrie[T]) LeafsPaths() [][]int { } func (t *BinaryTrie[T]) String(printOnLeaf func(*BinaryTrie[T]) string) { - t.forEachStepDown(func(node *BinaryTrie[T]) { + t.ForEachStepDown(func(node *BinaryTrie[T]) { if node.IsLeaf() { extra := "" if printOnLeaf != nil { From 61f473e52ec3fe14a409ce10182c310716b8d767 Mon Sep 17 00:00:00 2001 From: Khalid Nowaf Date: Mon, 1 Jul 2024 23:41:27 +0300 Subject: [PATCH 2/3] refactor(Supernet): create CidrTrie alias for trie.BinaryTrie[Metadata] --- pkg/supernet/action.go | 22 +++++++++++----------- pkg/supernet/conflict.go | 18 +++++++----------- pkg/supernet/option.go | 6 ++---- pkg/supernet/plan.go | 8 +++----- pkg/supernet/results.go | 16 +++++++--------- pkg/supernet/supernet.go | 18 ++++++++++-------- pkg/supernet/uitls.go | 4 +--- 7 files changed, 41 insertions(+), 51 deletions(-) diff --git a/pkg/supernet/action.go b/pkg/supernet/action.go index d74c3e5..a2562b5 100644 --- a/pkg/supernet/action.go +++ b/pkg/supernet/action.go @@ -5,7 +5,7 @@ import ( ) type Action interface { - Execute(newCidr *trie.BinaryTrie[Metadata], conflictedPoint *trie.BinaryTrie[Metadata], targetNode *trie.BinaryTrie[Metadata], remainingPath []int) *ActionResult + Execute(newCidr *CidrTrie, conflictedPoint *CidrTrie, targetNode *CidrTrie, remainingPath []int) *ActionResult String() string } @@ -17,7 +17,7 @@ type ( SplitExistingCIDR struct{} // split the existing CIDR `on` specific node ) -func (action IgnoreInsertion) Execute(_ *trie.BinaryTrie[Metadata], _ *trie.BinaryTrie[Metadata], _ *trie.BinaryTrie[Metadata], _ []int) *ActionResult { +func (action IgnoreInsertion) Execute(_ *CidrTrie, _ *CidrTrie, _ *CidrTrie, _ []int) *ActionResult { return &ActionResult{ Action: action, } @@ -27,7 +27,7 @@ func (_ IgnoreInsertion) String() string { return "Ignore Insertion" } -func (action InsertNewCIDR) Execute(newCidr *trie.BinaryTrie[Metadata], conflictedPoint *trie.BinaryTrie[Metadata], _ *trie.BinaryTrie[Metadata], remainingPath []int) *ActionResult { +func (action InsertNewCIDR) Execute(newCidr *CidrTrie, conflictedPoint *CidrTrie, _ *CidrTrie, remainingPath []int) *ActionResult { actionResult := &ActionResult{ Action: action, @@ -60,7 +60,7 @@ func (_ InsertNewCIDR) String() string { return "Insert New CIDR" } -func (action RemoveExistingCIDR) Execute(newCidr *trie.BinaryTrie[Metadata], _ *trie.BinaryTrie[Metadata], targetNode *trie.BinaryTrie[Metadata], _ []int) *ActionResult { +func (action RemoveExistingCIDR) Execute(newCidr *CidrTrie, _ *CidrTrie, targetNode *CidrTrie, _ []int) *ActionResult { actionResult := &ActionResult{ Action: action, @@ -83,7 +83,7 @@ func (_ RemoveExistingCIDR) String() string { return "Remove Existing CIDR" } -func (action SplitInsertedCIDR) Execute(newCidr *trie.BinaryTrie[Metadata], conflictedPoint *trie.BinaryTrie[Metadata], targetNode *trie.BinaryTrie[Metadata], _ []int) *ActionResult { +func (action SplitInsertedCIDR) Execute(newCidr *CidrTrie, conflictedPoint *CidrTrie, targetNode *CidrTrie, _ []int) *ActionResult { actionResult := &ActionResult{ Action: action, @@ -103,7 +103,7 @@ func (_ SplitInsertedCIDR) String() string { return "Split Inserted CIDR" } -func (action SplitExistingCIDR) Execute(newCidr *trie.BinaryTrie[Metadata], conflictedPoint *trie.BinaryTrie[Metadata], targetNode *trie.BinaryTrie[Metadata], _ []int) *ActionResult { +func (action SplitExistingCIDR) Execute(newCidr *CidrTrie, conflictedPoint *CidrTrie, targetNode *CidrTrie, _ []int) *ActionResult { // init inserted result actionResult := &ActionResult{ Action: action, @@ -123,23 +123,23 @@ func (_ SplitExistingCIDR) String() string { } // to keep track of all removed CIDRs from resolving a conflict. -func (ar *ActionResult) appendRemovedCidr(cidr *trie.BinaryTrie[Metadata]) { +func (ar *ActionResult) appendRemovedCidr(cidr *CidrTrie) { ar.RemoveCidrs = append(ar.RemoveCidrs, *cidr) } // The function traverses from the sub-CIDR node upwards, attempting to insert a sibling node at each step. // If a sibling node at a given position does not exist, it is created and added. The traversal and modifications // stop when reaching the depth of the super-CIDR node. -func splitAround(sub *trie.BinaryTrie[Metadata], newCidrMetadata *Metadata, limitDepth int) []*trie.BinaryTrie[Metadata] { +func splitAround(sub *CidrTrie, newCidrMetadata *Metadata, limitDepth int) []*CidrTrie { splittedCidrMetadata := newCidrMetadata if splittedCidrMetadata == nil { panic("[BUG] splitAround: Metadata is required to split a supernet") } - var splittedCidrs []*trie.BinaryTrie[Metadata] + var splittedCidrs []*CidrTrie - sub.ForEachStepUp(func(current *trie.BinaryTrie[Metadata]) { + sub.ForEachStepUp(func(current *CidrTrie) { // Create a new trie node with the same metadata as the splittedCidrMetadata. newCidr := trie.NewTrieWithMetadata(&Metadata{ @@ -156,7 +156,7 @@ func splitAround(sub *trie.BinaryTrie[Metadata], newCidrMetadata *Metadata, limi splittedCidrs = append(splittedCidrs, added) } else { } - }, func(nextNode *trie.BinaryTrie[Metadata]) bool { + }, func(nextNode *CidrTrie) bool { // Stop propagation when reaching the depth of the super-CIDR. return nextNode.Depth() > limitDepth }) diff --git a/pkg/supernet/conflict.go b/pkg/supernet/conflict.go index a256a70..33736e3 100644 --- a/pkg/supernet/conflict.go +++ b/pkg/supernet/conflict.go @@ -1,12 +1,8 @@ package supernet -import ( - "github.com/khalid-nowaf/supernet/pkg/trie" -) - type ConflictType interface { String() string - Resolve(conflictedCidr *trie.BinaryTrie[Metadata], newCidr *trie.BinaryTrie[Metadata], comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan + Resolve(conflictedCidr *CidrTrie, newCidr *CidrTrie, comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan } type ( @@ -16,7 +12,7 @@ type ( SubCIDR struct{} // the new CIDR is a sub CIDR of an existing super CIDR ) -func (_ NoConflict) Resolve(at *trie.BinaryTrie[Metadata], newCidr *trie.BinaryTrie[Metadata], comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { +func (_ NoConflict) Resolve(at *CidrTrie, newCidr *CidrTrie, comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { plan := &ResolutionPlan{} plan.AddAction(InsertNewCIDR{}, at) return plan @@ -26,7 +22,7 @@ func (_ NoConflict) String() string { return "No Conflict" } -func (_ EqualCIDR) Resolve(conflictedCidr *trie.BinaryTrie[Metadata], newCidr *trie.BinaryTrie[Metadata], comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { +func (_ EqualCIDR) Resolve(conflictedCidr *CidrTrie, newCidr *CidrTrie, comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { plan := &ResolutionPlan{} plan.Conflicts = append(plan.Conflicts, *conflictedCidr) if comparator(newCidr.Metadata(), conflictedCidr.Metadata()) { @@ -44,15 +40,15 @@ func (_ EqualCIDR) String() string { return "Equal CIDR" } -func (_ SuperCIDR) Resolve(conflictPoint *trie.BinaryTrie[Metadata], newSuperCidr *trie.BinaryTrie[Metadata], comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { +func (_ SuperCIDR) Resolve(conflictPoint *CidrTrie, newSuperCidr *CidrTrie, comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { plan := &ResolutionPlan{} // since this is a super, we do not know how many subcidrs yet conflicting with this super // let us get all subCidrs conflictedSubCidrs := conflictPoint.Leafs() - subCidrsWithLowPriority := []*trie.BinaryTrie[Metadata]{} - subCidrsWithHighPriority := []*trie.BinaryTrie[Metadata]{} + subCidrsWithLowPriority := []*CidrTrie{} + subCidrsWithHighPriority := []*CidrTrie{} for _, conflictedSubCidr := range conflictedSubCidrs { plan.Conflicts = append(plan.Conflicts, *conflictedSubCidr) @@ -86,7 +82,7 @@ func (_ SuperCIDR) String() string { return "Super CIDR" } -func (_ SubCIDR) Resolve(existingSuperCidr *trie.BinaryTrie[Metadata], newSubCidr *trie.BinaryTrie[Metadata], comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { +func (_ SubCIDR) Resolve(existingSuperCidr *CidrTrie, newSubCidr *CidrTrie, comparator func(a *Metadata, b *Metadata) bool) *ResolutionPlan { plan := &ResolutionPlan{} plan.Conflicts = append(plan.Conflicts, *existingSuperCidr) // since this is a SubCidr, we have 2 option diff --git a/pkg/supernet/option.go b/pkg/supernet/option.go index 58455fb..1da5ba7 100644 --- a/pkg/supernet/option.go +++ b/pkg/supernet/option.go @@ -2,8 +2,6 @@ package supernet import ( "fmt" - - "github.com/khalid-nowaf/supernet/pkg/trie" ) type Option func(*Supernet) *Supernet @@ -12,8 +10,8 @@ type LoggerOption func(*InsertionResult) func DefaultOptions() *Supernet { return &Supernet{ - ipv4Cidrs: &trie.BinaryTrie[Metadata]{}, - ipv6Cidrs: &trie.BinaryTrie[Metadata]{}, + ipv4Cidrs: &CidrTrie{}, + ipv6Cidrs: &CidrTrie{}, comparator: DefaultComparator, logger: func(ir *InsertionResult) {}, } diff --git a/pkg/supernet/plan.go b/pkg/supernet/plan.go index 91d82a5..fc9d8af 100644 --- a/pkg/supernet/plan.go +++ b/pkg/supernet/plan.go @@ -1,17 +1,15 @@ package supernet -import "github.com/khalid-nowaf/supernet/pkg/trie" - type PlanStep struct { Action Action - TargetNode *trie.BinaryTrie[Metadata] + TargetNode *CidrTrie } type ResolutionPlan struct { - Conflicts []trie.BinaryTrie[Metadata] + Conflicts []CidrTrie Steps []*PlanStep } -func (plan *ResolutionPlan) AddAction(action Action, on *trie.BinaryTrie[Metadata]) { +func (plan *ResolutionPlan) AddAction(action Action, on *CidrTrie) { plan.Steps = append(plan.Steps, &PlanStep{ Action: action, TargetNode: on, diff --git a/pkg/supernet/results.go b/pkg/supernet/results.go index 8e46125..616e3ae 100644 --- a/pkg/supernet/results.go +++ b/pkg/supernet/results.go @@ -3,16 +3,14 @@ package supernet import ( "fmt" "net" - - "github.com/khalid-nowaf/supernet/pkg/trie" ) // records the outcome of attempting to insert a CIDR for reporting type InsertionResult struct { - CIDR *net.IPNet // CIDR was attempted to be inserted. - actions []*ActionResult // the result of each action is taken - ConflictedWith []trie.BinaryTrie[Metadata] // array of conflicting nodes - ConflictType // the type of the conflict + CIDR *net.IPNet // CIDR was attempted to be inserted. + actions []*ActionResult // the result of each action is taken + ConflictedWith []CidrTrie // array of conflicting nodes + ConflictType // the type of the conflict } func (ir *InsertionResult) String() string { @@ -36,8 +34,8 @@ func (ir *InsertionResult) String() string { type ActionResult struct { Action Action - AddedCidrs []trie.BinaryTrie[Metadata] - RemoveCidrs []trie.BinaryTrie[Metadata] + AddedCidrs []CidrTrie + RemoveCidrs []CidrTrie } func (ar ActionResult) String() string { @@ -56,6 +54,6 @@ func (ar ActionResult) String() string { } // to keep track of all the added CIDRs from resolving a conflict. -func (ar *ActionResult) appendAddedCidr(cidr *trie.BinaryTrie[Metadata]) { +func (ar *ActionResult) appendAddedCidr(cidr *CidrTrie) { ar.AddedCidrs = append(ar.AddedCidrs, *cidr) } diff --git a/pkg/supernet/supernet.go b/pkg/supernet/supernet.go index 69c549c..c2327cf 100644 --- a/pkg/supernet/supernet.go +++ b/pkg/supernet/supernet.go @@ -8,6 +8,8 @@ import ( "github.com/khalid-nowaf/supernet/pkg/trie" ) +type CidrTrie = trie.BinaryTrie[Metadata] + // holds the properties for a CIDR node type Metadata struct { originCIDR *net.IPNet // copy of the CIDR, to track it, if it get splitted later due to conflict resolution @@ -30,8 +32,8 @@ func NewMetadata(ipnet *net.IPNet) *Metadata { // Supernet represents a structure containing both IPv4 and IPv6 CIDRs, each stored in a separate trie. type Supernet struct { - ipv4Cidrs *trie.BinaryTrie[Metadata] - ipv6Cidrs *trie.BinaryTrie[Metadata] + ipv4Cidrs *CidrTrie + ipv6Cidrs *CidrTrie comparator ComparatorOption logger LoggerOption } @@ -114,7 +116,7 @@ func (super *Supernet) LookupIP(ip string) (*net.IPNet, error) { } // retrieves all CIDRs from the specified IPv4 or IPv6 trie within a supernet. -func (super *Supernet) AllCIDRS(forV6 bool) []*trie.BinaryTrie[Metadata] { +func (super *Supernet) AllCIDRS(forV6 bool) []*CidrTrie { supernet := super.ipv4Cidrs if forV6 { supernet = super.ipv6Cidrs @@ -136,12 +138,12 @@ func (super *Supernet) AllCidrsString(forV6 bool) []string { } // creates a new trie node intended for path utilization without any associated metadata. -func newPathNode() *trie.BinaryTrie[Metadata] { - return &trie.BinaryTrie[Metadata]{} +func newPathNode() *CidrTrie { + return &CidrTrie{} } // build the CIDR path, and report any conflict -func buildPath(root *trie.BinaryTrie[Metadata], path []int) (lastNode *trie.BinaryTrie[Metadata], conflict ConflictType, remainingPath []int) { +func buildPath(root *CidrTrie, path []int) (lastNode *CidrTrie, conflict ConflictType, remainingPath []int) { currentNode := root for currentDepth, bit := range path { // add a pathNode, if the current node is nil @@ -158,7 +160,7 @@ func buildPath(root *trie.BinaryTrie[Metadata], path []int) (lastNode *trie.Bina } // try to build the CIDR path, and handle any conflict if any -func (super Supernet) insertLeaf(root *trie.BinaryTrie[Metadata], path []int, newCidrNode *trie.BinaryTrie[Metadata]) *InsertionResult { +func (super Supernet) insertLeaf(root *CidrTrie, path []int, newCidrNode *CidrTrie) *InsertionResult { insertionResults := &InsertionResult{ CIDR: newCidrNode.Metadata().originCIDR, } @@ -183,7 +185,7 @@ func (super Supernet) insertLeaf(root *trie.BinaryTrie[Metadata], path []int, ne } // CIDR conflict detection, it check the current node if it conflicts with other CIDRS -func isThereAConflict(currentNode *trie.BinaryTrie[Metadata], targetedDepth int) ConflictType { +func isThereAConflict(currentNode *CidrTrie, targetedDepth int) ConflictType { // Check if the current node is a new or path node without specific metadata. if currentNode.Metadata() == nil { // Determine if the current node is a supernet of the targeted CIDR. diff --git a/pkg/supernet/uitls.go b/pkg/supernet/uitls.go index 1592294..e53d906 100644 --- a/pkg/supernet/uitls.go +++ b/pkg/supernet/uitls.go @@ -2,8 +2,6 @@ package supernet import ( "net" - - "github.com/khalid-nowaf/supernet/pkg/trie" ) // BitsToCidr converts a slice of binary bits into a net.IPNet structure that represents a CIDR. @@ -75,7 +73,7 @@ func BitsToCidr(bits []int, ipV6 bool) *net.IPNet { // // Given a trie node representing an IP address with metadata, this function will output the address in CIDR format, // like "192.168.1.0/24" for IPv4 or "2001:db8::/32" for IPv6. -func NodeToCidr(t *trie.BinaryTrie[Metadata]) string { +func NodeToCidr(t *CidrTrie) string { if t.Metadata() == nil { panic("[Bug] NodeToCidr: Cannot convert a trie path node to CIDR, metadata is missing") } From 0b577a623d4450c23bb9dbd33fd67211cc3737c4 Mon Sep 17 00:00:00 2001 From: Khalid Nowaf Date: Mon, 1 Jul 2024 23:43:03 +0300 Subject: [PATCH 3/3] fix(CLI): import paths --- cmd/supernet/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/supernet/main.go b/cmd/supernet/main.go index c3f214a..1157409 100644 --- a/cmd/supernet/main.go +++ b/cmd/supernet/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/khalid_nowaf/supernet/pkg/cli" - "github.com/khalid_nowaf/supernet/pkg/supernet" + "github.com/khalid-nowaf/supernet/pkg/cli" + "github.com/khalid-nowaf/supernet/pkg/supernet" ) func main() {