Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize algorithm #195

Open
wants to merge 78 commits into
base: optimize
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
7e70c95
fixed
YairSlobodin1 Aug 26, 2024
19123f9
minor change
YairSlobodin1 Aug 26, 2024
20ab99f
Merge branch 'optimize' into read_sgs
YairSlobodin1 Aug 26, 2024
2b7f244
added synth prefix
YairSlobodin1 Aug 26, 2024
8203f78
unexported two functions
YairSlobodin1 Aug 26, 2024
5fbeefc
wip
YairSlobodin1 Aug 26, 2024
b228063
Merge branch 'optimize' into read_sgs
YairSlobodin1 Aug 26, 2024
ebe6148
Merge branch 'read_sgs' into output
YairSlobodin1 Aug 26, 2024
d17ce6d
Merge branch 'optimize' into read_sgs
YairSlobodin1 Aug 26, 2024
32f3104
Merge branch 'read_sgs' into output
YairSlobodin1 Aug 26, 2024
02030ac
updated
YairSlobodin1 Aug 26, 2024
47fe8bb
merge
YairSlobodin1 Aug 26, 2024
1371e59
Merge branch 'read_sgs' into output
YairSlobodin1 Aug 26, 2024
0c9cfe2
wip
YairSlobodin1 Aug 26, 2024
eebd628
template
YairSlobodin1 Aug 27, 2024
26473b3
done
YairSlobodin1 Aug 28, 2024
010ee9d
fixed
YairSlobodin1 Sep 1, 2024
524956c
fixed
YairSlobodin1 Sep 2, 2024
a005a82
Merge branch 'optimize' into read_sgs
YairSlobodin1 Sep 2, 2024
9692f06
Merge branch 'read_sgs' into output
YairSlobodin1 Sep 2, 2024
002a952
Merge branch 'output' into tcp_algo
YairSlobodin1 Sep 2, 2024
aabe195
wip
YairSlobodin1 Sep 2, 2024
b163645
wip
YairSlobodin1 Sep 3, 2024
1e9a621
wip
YairSlobodin1 Sep 8, 2024
c4f9ed4
wip
YairSlobodin1 Sep 8, 2024
a683181
Merge branch 'optimize' into read_sgs
YairSlobodin1 Sep 8, 2024
77a3fe0
Merge branch 'read_sgs' into output
YairSlobodin1 Sep 8, 2024
e3fb24b
Merge branch 'output' into all_algo
YairSlobodin1 Sep 8, 2024
a7f68f5
lint
YairSlobodin1 Sep 11, 2024
8e5cb2d
wip
YairSlobodin1 Sep 11, 2024
a861722
wip
YairSlobodin1 Sep 12, 2024
380c62e
fixed
YairSlobodin1 Sep 12, 2024
c22aad0
fixed
YairSlobodin1 Sep 12, 2024
81f6194
fixed
YairSlobodin1 Sep 12, 2024
197ed31
fixed
YairSlobodin1 Sep 12, 2024
3ab9859
merge
YairSlobodin1 Sep 12, 2024
9078e5c
wip
YairSlobodin1 Sep 12, 2024
dfb8a7d
wip
YairSlobodin1 Sep 12, 2024
8895149
implement ip functions
YairSlobodin1 Sep 12, 2024
c8fe2d7
all protocol rule covers the holes
YairSlobodin1 Sep 12, 2024
0a0decd
wip
YairSlobodin1 Sep 24, 2024
cf119cc
wip
YairSlobodin1 Sep 24, 2024
a51e158
documentation
YairSlobodin1 Sep 24, 2024
f93c27c
Merge branch 'optimize' into read_sgs
YairSlobodin1 Sep 25, 2024
6be5ee0
fixed
YairSlobodin1 Sep 25, 2024
2f9991a
wip
YairSlobodin1 Sep 25, 2024
bf9438f
wip
YairSlobodin1 Sep 25, 2024
e3d4668
wip
YairSlobodin1 Sep 25, 2024
ebb4b3b
wip
YairSlobodin1 Sep 25, 2024
f34b9b7
fixed
YairSlobodin1 Sep 25, 2024
f228c0b
Merge branch 'optimize' into read_sgs
YairSlobodin1 Sep 25, 2024
d3c7703
Merge branch 'read_sgs' into output
YairSlobodin1 Sep 25, 2024
b2b0b99
merge
YairSlobodin1 Sep 25, 2024
5001289
Merge branch 'optimize' into read_sgs
YairSlobodin1 Sep 29, 2024
a89e1fe
merge
YairSlobodin1 Sep 29, 2024
16764ca
Merge branch 'output' into all_algo
YairSlobodin1 Sep 29, 2024
ca64cee
avoid code dup
YairSlobodin1 Sep 30, 2024
49f4a47
fixed
YairSlobodin1 Sep 30, 2024
766f737
fix output fmts
YairSlobodin1 Sep 30, 2024
d326453
Merge branch 'output' into all_algo
YairSlobodin1 Sep 30, 2024
e6bb1b3
tests template
YairSlobodin1 Sep 30, 2024
34410ed
tests data
YairSlobodin1 Sep 30, 2024
28a55ec
wip
YairSlobodin1 Sep 30, 2024
3145c59
merge
YairSlobodin1 Oct 1, 2024
cd621ce
Merge branch 'output' into all_algo
YairSlobodin1 Oct 1, 2024
2de0e77
wip
YairSlobodin1 Oct 1, 2024
b496279
wip
YairSlobodin1 Oct 2, 2024
bca5f6f
Merge branch 'optimize' into all_algo
YairSlobodin1 Oct 7, 2024
11effb7
fix merging
YairSlobodin1 Oct 7, 2024
2bb0719
models new version, cubes, wip
YairSlobodin1 Oct 8, 2024
fadb26b
portset
YairSlobodin1 Oct 9, 2024
3cdadc6
convert ip cubes, generic ipCubeToRule
YairSlobodin1 Oct 9, 2024
69ca412
delete test
YairSlobodin1 Oct 9, 2024
c2512d9
make fmt
YairSlobodin1 Oct 9, 2024
28c3a3b
remove utils func
YairSlobodin1 Oct 9, 2024
9cd8663
models v0.5.1
YairSlobodin1 Oct 9, 2024
da1c7d2
fixed
YairSlobodin1 Oct 9, 2024
4f54945
another test, fixed icmp bug
YairSlobodin1 Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/subcmds/optimizeSG.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package subcmds
import (
"github.com/spf13/cobra"

"github.com/np-guard/vpc-network-config-synthesis/pkg/optimize"
sgoptimizer "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize/sg"
)

const sgNameFlag = "sg-name"
Expand All @@ -20,7 +20,7 @@ func NewOptimizeSGCommand(args *inArgs) *cobra.Command {
Long: `OptimizeSG attempts to reduce the number of security group rules in a SG without changing the semantic.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
return optimization(cmd, args, optimize.NewSGOptimizer, true)
return optimization(cmd, args, sgoptimizer.NewSGOptimizer, true)
},
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.23.0
require (
github.com/IBM/vpc-go-sdk v0.60.0
github.com/np-guard/cloud-resource-collector v0.15.0
github.com/np-guard/models v0.5.0
github.com/np-guard/models v0.5.1
github.com/spf13/cobra v1.8.1
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/np-guard/cloud-resource-collector v0.15.0 h1:jkmxql6D1uBr/qmSOsBzUgeDxlUXSCe7dBKfqfK+QZ4=
github.com/np-guard/cloud-resource-collector v0.15.0/go.mod h1:klCHnNnuuVcCtGQHA7R1a8fqnvfMCk/5Jdld6V7sN2A=
github.com/np-guard/models v0.5.0 h1:P37gCg3RD23hZHymFWtthrF+mGIwyHJkWy0wIWIzokQ=
github.com/np-guard/models v0.5.0/go.mod h1:29M8utxinyUpYaDuIuOyCcMBf7EsMWZcIrRWCjFm0Bw=
github.com/np-guard/models v0.5.1 h1:qxewCB3cBLkBdcpMk05gKJkV1D7qkbteQdIXbN1juW0=
github.com/np-guard/models v0.5.1/go.mod h1:29M8utxinyUpYaDuIuOyCcMBf7EsMWZcIrRWCjFm0Bw=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
Expand Down
2 changes: 1 addition & 1 deletion pkg/io/confio/parse_sgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func translateSGRuleProtocolIcmp(rule *vpcv1.SecurityGroupRuleSecurityGroupRuleP
if err != nil {
return nil, err
}
protocol, err := netp.ICMPFromTypeAndCode64(rule.Type, rule.Code)
protocol, err := netp.ICMPFromTypeAndCode64WithoutRFCValidation(rule.Type, rule.Code)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/io/tfio/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func aclRule(rule *ir.ACLRule, name string) (tf.Block, error) {
{Name: "destination", Value: quote(rule.Destination.String())},
}

comment := ""
comment := "\n"
if rule.Explanation != "" {
comment = fmt.Sprintf("# %v", rule.Explanation)
}
Expand Down Expand Up @@ -109,7 +109,7 @@ func aclCollection(t *ir.ACLCollection, vpc string) (*tf.ConfigFile, error) {
var acls = make([]tf.Block, len(sortedACLs))
i := 0
for _, subnet := range sortedACLs {
comment := ""
comment := "\n"
vpcName := ir.VpcFromScopedResource(subnet)
acl := t.ACLs[vpcName][subnet]
if len(sortedACLs) > 1 { // not a single nacl
Expand Down
4 changes: 2 additions & 2 deletions pkg/io/tfio/sg.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ func sgRule(rule *ir.SGRule, sgName ir.SGName, i int) (tf.Block, error) {
func sg(sgName, vpcName string) (tf.Block, error) {
tfSGName := ir.ChangeScoping(sgName)
comment := fmt.Sprintf("\n### SG attached to %s", sgName)
if sgName == tfSGName { // its optimization
comment = ""
if sgName == tfSGName { // optimization mode
comment = "\n"
}
if err := verifyName(tfSGName); err != nil {
return tf.Block{}, err
Expand Down
5 changes: 5 additions & 0 deletions pkg/ir/sg.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ func (r *SGRule) mustSupersede(other *SGRule) bool {
return res
}

func NewSGRule(direction Direction, remote RemoteType, p netp.Protocol, local *netset.IPBlock, e string) *SGRule {
return &SGRule{Direction: direction, Remote: remote, Protocol: p,
Local: local, Explanation: e}
}

func NewSG(sgName SGName) *SG {
return &SG{SGName: sgName, InboundRules: []*SGRule{}, OutboundRules: []*SGRule{}, Attached: []ID{}}
}
Expand Down
69 changes: 68 additions & 1 deletion pkg/optimize/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,76 @@ SPDX-License-Identifier: Apache-2.0

package optimize

import "github.com/np-guard/vpc-network-config-synthesis/pkg/ir"
import (
"sort"

"github.com/np-guard/models/pkg/ds"
"github.com/np-guard/models/pkg/netp"
"github.com/np-guard/models/pkg/netset"

"github.com/np-guard/vpc-network-config-synthesis/pkg/ir"
)

type Optimizer interface {
// attempts to reduce number of SG/nACL rules
Optimize() (ir.Collection, error)
}

// each IPBlock is a single CIDR. The CIDRs are disjoint.
func SortPartitionsByIPAddrs[T any](p []ds.Pair[*netset.IPBlock, T]) []ds.Pair[*netset.IPBlock, T] {
cmp := func(i, j int) bool {
if p[i].Left.FirstIPAddress() == p[j].Left.FirstIPAddress() {
return p[i].Left.LastIPAddress() < p[j].Left.LastIPAddress()
}
return p[i].Left.FirstIPAddress() < p[j].Left.FirstIPAddress()
}
sort.Slice(p, cmp)
return p
}

// returns true if this<other
func LessIPBlock(this, other *netset.IPBlock) bool {
if this.FirstIPAddress() == other.FirstIPAddress() {
return this.LastIPAddress() < other.LastIPAddress()
}
return this.FirstIPAddress() < other.FirstIPAddress()
}

func IcmpsetPartitions(icmpset *netset.ICMPSet) []netp.ICMP {
result := make([]netp.ICMP, 0)
if icmpset.IsAll() {
icmp, _ := netp.ICMPFromTypeAndCode64WithoutRFCValidation(nil, nil)
return []netp.ICMP{icmp}
}

for _, cube := range icmpset.Partitions() {
for _, typeInterval := range cube.Left.Intervals() {
for _, icmpType := range typeInterval.Elements() {
if cube.Right.Equal(netset.AllICMPCodes()) {
icmp, _ := netp.ICMPFromTypeAndCode64WithoutRFCValidation(&icmpType, nil)
result = append(result, icmp)
continue
}
for _, codeInterval := range cube.Right.Intervals() {
for _, icmpCode := range codeInterval.Elements() {
icmp, _ := netp.ICMPFromTypeAndCode64WithoutRFCValidation(&icmpType, &icmpCode)
result = append(result, icmp)
}
}
}
}
}
return result
}

func IcmpRuleToIcmpSet(icmp netp.ICMP) *netset.ICMPSet {
if icmp.TypeCode == nil {
return netset.AllICMPSet()
}
icmpType := int64(icmp.TypeCode.Type)
if icmp.TypeCode.Code == nil {
return netset.NewICMPSet(icmpType, icmpType, int64(netp.MinICMPCode), int64(netp.MaxICMPCode))
}
icmpCode := int64(*icmp.TypeCode.Code)
return netset.NewICMPSet(icmpType, icmpType, icmpCode, icmpCode)
}
28 changes: 0 additions & 28 deletions pkg/optimize/sg.go

This file was deleted.

143 changes: 143 additions & 0 deletions pkg/optimize/sg/ipCubesToRules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
Copyright 2023- IBM Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package sgoptimizer

import (
"github.com/np-guard/models/pkg/ds"
"github.com/np-guard/models/pkg/interval"
"github.com/np-guard/models/pkg/netp"
"github.com/np-guard/models/pkg/netset"

"github.com/np-guard/vpc-network-config-synthesis/pkg/ir"
"github.com/np-guard/vpc-network-config-synthesis/pkg/optimize"
)

// all protocol cubes, represented by a single ipblock that will be decomposed
// into cidrs. Each cidr will be the remote of a SG rule
func allProtocolIPCubesIPToRules(cubes *netset.IPBlock, direction ir.Direction) []*ir.SGRule {
result := make([]*ir.SGRule, 0)
for _, cidr := range cubes.SplitToCidrs() {
result = append(result, ir.NewSGRule(direction, cidr, netp.AnyProtocol{}, netset.GetCidrAll(), ""))
}
return result
}

// tcpudpIPCubesToRules converts cubes representing tcp or udp protocol rules to SG rules
func tcpudpIPCubesToRules(cubes []ds.Pair[*netset.IPBlock, *netset.PortSet], allCubes *netset.IPBlock, direction ir.Direction,
isTCP bool) []*ir.SGRule {
if len(cubes) == 0 {
return []*ir.SGRule{}
}

activeRules := make(map[*netset.IPBlock]netp.Protocol) // the key is the first IP
result := make([]*ir.SGRule, 0)

for i := range cubes {
// if it is not possible to continue the rule between the cubes, generate all the existing rules
if i > 0 && !continuation(cubes[i-1], cubes[i], allCubes) {
result = append(result, createActiveRules(activeRules, cubes[i-1].Left.LastIPAddressObject(), direction)...)
activeRules = make(map[*netset.IPBlock]netp.Protocol)
}

// if the proctol is not contained in the current cube, we will generate SG rules
// calculate active ports = active rules covers these ports
activePorts := interval.NewCanonicalSet()
for ipb, protocol := range activeRules {
if tcpudp, ok := protocol.(netp.TCPUDP); ok {
if !tcpudp.DstPorts().ToSet().IsSubset(cubes[i].Right) {
result = append(result, createNewRules(protocol, ipb, cubes[i-1].Left.LastIPAddressObject(), direction)...)
} else {
activePorts.AddInterval(tcpudp.DstPorts())
}
}
}

// if the cube contains ports that are not contained in the active rules, new rules will be created
for _, ports := range cubes[i].Right.Intervals() {
if !ports.ToSet().IsSubset(activePorts) {
p, _ := netp.NewTCPUDP(isTCP, netp.MinPort, netp.MaxPort, int(ports.Start()), int(ports.End()))
activeRules[cubes[i].Left.FirstIPAddressObject()] = p
}
}
}
// generate all the existing rules
return append(result, createActiveRules(activeRules, cubes[len(cubes)-1].Left.LastIPAddressObject(), direction)...)
}

// icmpIPCubesToRules converts cubes representing icmp protocol rules to SG rules
func icmpIPCubesToRules(cubes []ds.Pair[*netset.IPBlock, *netset.ICMPSet], allCubes *netset.IPBlock, direction ir.Direction) []*ir.SGRule {
if len(cubes) == 0 {
return []*ir.SGRule{}
}

activeRules := make(map[*netset.IPBlock]netp.Protocol) // the key is the first IP
result := make([]*ir.SGRule, 0)

for i := range cubes {
// if it is not possible to continue the rule between the cubes, generate all the existing rules
if i > 0 && !continuation(cubes[i-1], cubes[i], allCubes) {
result = append(result, createActiveRules(activeRules, cubes[i-1].Left.LastIPAddressObject(), direction)...)
activeRules = make(map[*netset.IPBlock]netp.Protocol)
}

// if the proctol is not contained in the current cube, we will generate SG rules
// calculate activeICMP = active rules covers these icmp values
activeICMP := netset.EmptyICMPSet()
for ipb, protocol := range activeRules {
if icmp, ok := protocol.(netp.ICMP); ok {
ruleIcmpSet := optimize.IcmpRuleToIcmpSet(icmp)
if !ruleIcmpSet.IsSubset(cubes[i].Right) {
result = append(result, createNewRules(protocol, ipb, cubes[i-1].Left.LastIPAddressObject(), direction)...)
} else {
activeICMP.Union(ruleIcmpSet)
}
}
}

// if the cube contains icmp values that are not contained in the active rules, new rules will be created
for _, p := range optimize.IcmpsetPartitions(cubes[i].Right) {
if !optimize.IcmpRuleToIcmpSet(p).IsSubset(activeICMP) {
activeRules[cubes[i].Left.FirstIPAddressObject()] = p
}
}
}

// generate all the existing rules
return append(result, createActiveRules(activeRules, cubes[len(cubes)-1].Left.LastIPAddressObject(), direction)...)
}

// continuation returns true if the rules can be continued between the two cubes
func continuation[T ds.Set[T]](prevPair, currPair ds.Pair[*netset.IPBlock, T], allProtocolCubes *netset.IPBlock) bool {
prevIPBlock := prevPair.Left
currIPBlock := currPair.Left
touching, _ := prevIPBlock.TouchingIPRanges(currIPBlock)
if touching {
return true
}
startH, _ := prevIPBlock.NextIP()
endH, _ := currIPBlock.PreviousIP()
hole, _ := netset.IPBlockFromIPRange(startH, endH)
return hole.IsSubset(allProtocolCubes)
}

// creates sgRules from SG active rules
func createActiveRules(activeRules map[*netset.IPBlock]netp.Protocol, endIP *netset.IPBlock, direction ir.Direction) []*ir.SGRule {
res := make([]*ir.SGRule, 0)
for ipb, protocol := range activeRules {
res = append(res, createNewRules(protocol, ipb, endIP, direction)...)
}
return res
}

// createNewRules breaks the startIP-endIP ip range into cidrs and creates SG rules
func createNewRules(protocol netp.Protocol, startIP, endIP *netset.IPBlock, direction ir.Direction) []*ir.SGRule {
res := make([]*ir.SGRule, 0)
ipRange, _ := netset.IPBlockFromIPRange(startIP, endIP)
for _, cidr := range ipRange.SplitToCidrs() {
res = append(res, ir.NewSGRule(direction, cidr, protocol, netset.GetCidrAll(), ""))
}
return res
}
Loading
Loading