Skip to content

Commit

Permalink
Revert "feat: remove optimizer from main repo"
Browse files Browse the repository at this point in the history
This reverts commit 57768db
  • Loading branch information
natesales committed Jul 9, 2024
1 parent 4cb1480 commit 02023ba
Show file tree
Hide file tree
Showing 12 changed files with 535 additions and 3 deletions.
11 changes: 10 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
dep:
pip3 install flask

dummy-iface:
# Allow UDP ping. For more information, see https://github.com/go-ping/ping#linux
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
sudo ip link add dev dummy0 type dummy
sudo ip addr add dev dummy0 192.0.2.1/24
sudo ip addr add dev dummy0 2001:db8::1/64
sudo ip link set dev dummy0 up

peeringdb-test-harness:
nohup python3 tests/peeringdb/peeringdb-test-api.py &

test-setup: peeringdb-test-harness
test-setup: dummy-iface peeringdb-test-harness

test:
export PATHVECTOR_TEST=1 && go test -v -race -coverprofile=coverage.txt -covermode=atomic ./pkg/... ./cmd/...

test-teardown:
pkill -f tests/peeringdb/peeringdb-test-api.py
sudo ip link del dev dummy0
rm -f nohup.out

test-sequence: test-setup test test-teardown
Expand Down
40 changes: 40 additions & 0 deletions cmd/optimizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package cmd

import (
"fmt"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/natesales/pathvector/pkg/optimizer"
)

func init() {
rootCmd.AddCommand(optimizerCmd)
}

var optimizerCmd = &cobra.Command{
Use: "optimizer",
Short: "Start optimization daemon",
Run: func(cmd *cobra.Command, args []string) {
c, err := loadConfig()
if err != nil {
log.Fatal(err)
}

log.Infof("Starting optimizer")
sourceMap := map[string][]string{} // peer name to list of source addresses
for peerName, peerData := range c.Peers {
if peerData.OptimizerProbeSources != nil && len(*peerData.OptimizerProbeSources) > 0 {
sourceMap[fmt.Sprintf("%d%s%s", *peerData.ASN, optimizer.Delimiter, peerName)] = *peerData.OptimizerProbeSources
}
}
log.Debugf("Optimizer probe sources: %v", sourceMap)
if len(sourceMap) == 0 {
log.Fatal("No peers have optimization enabled, exiting now")
}
if err := optimizer.StartProbe(c.Optimizer, sourceMap, c, noConfigure, dryRun); err != nil {
log.Fatal(err)
}
},
}
44 changes: 44 additions & 0 deletions cmd/optimizer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cmd

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestOptimizer(t *testing.T) {
args := []string{
"--verbose",
}
files, err := filepath.Glob("../tests/probe-*.yml")
assert.Nil(t, err)
assert.GreaterOrEqual(t, 1, len(files))

for _, testFile := range files {
// Run pathvector to generate config first, so there is a config to modify
rootCmd.SetArgs(append(args, []string{
"generate",
"--config", testFile,
}...))
t.Logf("Running pre-optimizer generate: %v", args)
assert.Nil(t, rootCmd.Execute())

args = append(args, []string{
"optimizer",
"--config", testFile,
}...)
t.Logf("running probe integration with args %v", args)
rootCmd.SetArgs(args)
assert.Nil(t, rootCmd.Execute())

// Check if local pref is lowered
checkFile, err := os.ReadFile("test-cache/AS65510_EXAMPLE.conf")
assert.Nil(t, err)
if !strings.Contains(string(checkFile), "bgp_local_pref = 80; # pathvector:localpref") {
t.Errorf("expected bgp_local_pref = 80 but not found in file")
}
}
}
1 change: 1 addition & 0 deletions docs/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Available Commands:
match Find common IXPs for a given ASN
reload Reload a session
restart Restart a session
optimizer Start optimization daemon
status Show protocol status
version Show version information
Expand Down
114 changes: 114 additions & 0 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,14 @@ Kernel routing configuration options
|------|---------|------------|
| [Kernel](#kernel-1) | | |

### `optimizer`

Route optimizer options

| Type | Default | Validation |
|------|---------|------------|
| [Optimizer](#optimizer-1) | | |

### `plugins`

Plugin-specific configuration
Expand Down Expand Up @@ -572,6 +580,96 @@ Routing table to read from
| string | | |


## Optimizer
### `targets`

List of probe targets

| Type | Default | Validation |
|------|---------|------------|
| []string | | |

### `latency-threshold`

Maximum allowable latency in milliseconds

| Type | Default | Validation |
|------|---------|------------|
| uint | 100 | |

### `packet-loss-threshold`

Maximum allowable packet loss (percent)

| Type | Default | Validation |
|------|---------|------------|
| float64 | 0.5 | |

### `modifier`

Amount to lower local pref by for depreferred peers

| Type | Default | Validation |
|------|---------|------------|
| uint | 20 | |

### `probe-count`

Number of pings to send in each run

| Type | Default | Validation |
|------|---------|------------|
| int | 5 | |

### `probe-timeout`

Number of seconds to wait before considering the ICMP message unanswered

| Type | Default | Validation |
|------|---------|------------|
| int | 1 | |

### `probe-interval`

Number of seconds wait between each optimizer run

| Type | Default | Validation |
|------|---------|------------|
| int | 120 | |

### `cache-size`

Number of probe results to store per peer

| Type | Default | Validation |
|------|---------|------------|
| int | 15 | |

### `probe-udp`

Use UDP probe (else ICMP)

| Type | Default | Validation |
|------|---------|------------|
| bool | false | |

### `alert-script`

Script to call on optimizer event

| Type | Default | Validation |
|------|---------|------------|
| string | | |

### `exit-on-cache-full`

Exit optimizer on cache full

| Type | Default | Validation |
|------|---------|------------|
| bool | false | |


## Peer
### `template`

Expand Down Expand Up @@ -1373,6 +1471,22 @@ Configuration to add after the export policy before the final accept/reject term
|------|---------|------------|
| string | | |

### `probe-sources`

Optimizer probe source addresses

| Type | Default | Validation |
|------|---------|------------|
| []string | | |

### `optimize-inbound`

Should the optimizer modify inbound policy?

| Type | Default | Validation |
|------|---------|------------|
| bool | false | |


## VRRPInstance
### `state`
Expand Down
37 changes: 37 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package config

import (
"github.com/go-ping/ping"
)

var defaultTransitASNs = []uint32{
174, // Cogent
// 209, // Qwest (HE carries this on IXPs IPv6 (Jul 12 2018))
Expand Down Expand Up @@ -219,6 +223,10 @@ type Peer struct {
PreExport *string `yaml:"pre-export" description:"Configuration to add before the export policy" default:"-"`
PreExportFinal *string `yaml:"pre-export-final" description:"Configuration to add after the export policy before the final accept/reject term" default:"-"`

// Optimizer
OptimizerProbeSources *[]string `yaml:"probe-sources" description:"Optimizer probe source addresses" default:"-"`
OptimizeInbound *bool `yaml:"optimize-inbound" description:"Should the optimizer modify inbound policy?" default:"false"`

ProtocolName *string `yaml:"-" description:"-" default:"-"`
UserSpecifiedName *string `yaml:"-" description:"-" default:"-"`
Protocols *[]string `yaml:"-" description:"-" default:"-"`
Expand Down Expand Up @@ -287,6 +295,33 @@ type Kernel struct {
KStatics6 map[string]string `yaml:"-" description:"-"`
}

// ProbeResult stores a single probe result
type ProbeResult struct {
Time int64
Stats ping.Statistics
}

// Optimizer stores route optimizer configuration
type Optimizer struct {
Targets []string `yaml:"targets" description:"List of probe targets"`
LatencyThreshold uint `yaml:"latency-threshold" description:"Maximum allowable latency in milliseconds" default:"100"`
PacketLossThreshold float64 `yaml:"packet-loss-threshold" description:"Maximum allowable packet loss (percent)" default:"0.5"`
LocalPrefModifier uint `yaml:"modifier" description:"Amount to lower local pref by for depreferred peers" default:"20"`

PingCount int `yaml:"probe-count" description:"Number of pings to send in each run" default:"5"`
PingTimeout int `yaml:"probe-timeout" description:"Number of seconds to wait before considering the ICMP message unanswered" default:"1"`
Interval int `yaml:"probe-interval" description:"Number of seconds wait between each optimizer run" default:"120"`
CacheSize int `yaml:"cache-size" description:"Number of probe results to store per peer" default:"15"`

ProbeUDPMode bool `yaml:"probe-udp" description:"Use UDP probe (else ICMP)" default:"false"`

AlertScript string `yaml:"alert-script" description:"Script to call on optimizer event"`

ExitOnCacheFull bool `yaml:"exit-on-cache-full" description:"Exit optimizer on cache full" default:"false"`

Db map[string][]ProbeResult `yaml:"-" description:"-"`
}

// Config stores the global configuration
type Config struct {
PeeringDBQueryTimeout uint `yaml:"peeringdb-query-timeout" description:"PeeringDB query timeout in seconds" default:"10"`
Expand Down Expand Up @@ -351,6 +386,7 @@ type Config struct {
BFDInstances map[string]*BFDInstance `yaml:"bfd" description:"BFD instances"`
MRTInstances map[string]*MRTInstance `yaml:"mrt" description:"MRT instances"`
Kernel *Kernel `yaml:"kernel" description:"Kernel routing configuration options"`
Optimizer *Optimizer `yaml:"optimizer" description:"Route optimizer options"`
Plugins map[string]string `yaml:"plugins" description:"Plugin-specific configuration"`

RTRServerHost string `yaml:"-" description:"-"`
Expand All @@ -377,6 +413,7 @@ func (c *Config) Init() {
c.BFDInstances = map[string]*BFDInstance{}
c.MRTInstances = map[string]*MRTInstance{}
c.Kernel = &Kernel{}
c.Optimizer = &Optimizer{}
c.Plugins = map[string]string{}

if c.TransitASNs == nil {
Expand Down
Loading

0 comments on commit 02023ba

Please sign in to comment.