From 862519ec19ff46ea5c01cc58f9d6ca0b38369851 Mon Sep 17 00:00:00 2001
From: Daniel Czerwonk <daniel@dan-nrw.de>
Date: Thu, 17 May 2018 11:32:49 +0200
Subject: [PATCH] copy paths, first path modification actions

---
 route/bgp.go                                  | 17 +++++++++++
 route/path.go                                 | 12 ++++++++
 route/static.go                               |  9 ++++++
 .../filter/actions/as_path_prepend_action.go  | 29 +++++++++++++++++++
 routingtable/filter/actions/filter_action.go  | 10 +++++++
 .../filter/actions/set_local_pref_action.go   |  9 +++---
 .../filter/actions/set_nexthop_action.go      | 13 ++++-----
 7 files changed, 87 insertions(+), 12 deletions(-)
 create mode 100644 routingtable/filter/actions/as_path_prepend_action.go
 create mode 100644 routingtable/filter/actions/filter_action.go

diff --git a/route/bgp.go b/route/bgp.go
index 47f7db4f..cde74bdd 100644
--- a/route/bgp.go
+++ b/route/bgp.go
@@ -154,6 +154,14 @@ func (b *BGPPath) Print() string {
 	return ret
 }
 
+func (b *BGPPath) Prepend(asn uint32, times uint16) {
+	for i := 0; uint16(i) < times; i++ {
+		b.ASPath = fmt.Sprintf("%d %s", asn, b.ASPath)
+	}
+
+	b.ASPathLen = b.ASPathLen + uint16(times)
+}
+
 func uint32To4Byte(addr uint32) [4]byte {
 	slice := convert.Uint32Byte(addr)
 	ret := [4]byte{
@@ -164,3 +172,12 @@ func uint32To4Byte(addr uint32) [4]byte {
 	}
 	return ret
 }
+
+func (p *BGPPath) Copy() *BGPPath {
+	if p == nil {
+		return nil
+	}
+
+	cp := *p
+	return &cp
+}
diff --git a/route/path.go b/route/path.go
index 544b83b4..ef2e8817 100644
--- a/route/path.go
+++ b/route/path.go
@@ -100,3 +100,15 @@ func (p *Path) Print() string {
 
 	return ret
 }
+
+func (p *Path) Copy() *Path {
+	if p == nil {
+		return nil
+	}
+
+	cp := *p
+	cp.BGPPath = cp.BGPPath.Copy()
+	cp.StaticPath = cp.StaticPath.Copy()
+
+	return &cp
+}
diff --git a/route/static.go b/route/static.go
index 483138f0..0ab6b26e 100644
--- a/route/static.go
+++ b/route/static.go
@@ -23,3 +23,12 @@ func (s *StaticPath) Compare(t *StaticPath) int8 {
 func (s *StaticPath) ECMP(t *StaticPath) bool {
 	return true
 }
+
+func (s *StaticPath) Copy() *StaticPath {
+	if s == nil {
+		return nil
+	}
+
+	cp := *s
+	return &cp
+}
diff --git a/routingtable/filter/actions/as_path_prepend_action.go b/routingtable/filter/actions/as_path_prepend_action.go
new file mode 100644
index 00000000..30d63ca7
--- /dev/null
+++ b/routingtable/filter/actions/as_path_prepend_action.go
@@ -0,0 +1,29 @@
+package actions
+
+import (
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+)
+
+type ASPathPrependAction struct {
+	asn   uint32
+	times uint16
+}
+
+func NewASPathPrependAction(asn uint32, times uint16) *ASPathPrependAction {
+	return &ASPathPrependAction{
+		asn:   asn,
+		times: times,
+	}
+}
+
+func (a *ASPathPrependAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
+	if pa.BGPPath == nil {
+		return pa, false
+	}
+
+	modified := pa.Copy()
+	modified.BGPPath.Prepend(a.asn, a.times)
+
+	return modified, false
+}
diff --git a/routingtable/filter/actions/filter_action.go b/routingtable/filter/actions/filter_action.go
new file mode 100644
index 00000000..7a266514
--- /dev/null
+++ b/routingtable/filter/actions/filter_action.go
@@ -0,0 +1,10 @@
+package actions
+
+import (
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+)
+
+type FilterAction interface {
+	Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool)
+}
diff --git a/routingtable/filter/actions/set_local_pref_action.go b/routingtable/filter/actions/set_local_pref_action.go
index 1b59be48..e60b6faa 100644
--- a/routingtable/filter/actions/set_local_pref_action.go
+++ b/routingtable/filter/actions/set_local_pref_action.go
@@ -3,20 +3,19 @@ package actions
 import (
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/route"
-	"github.com/bio-routing/bio-rd/routingtable/filter"
 )
 
-type setLocalPrefAction struct {
+type SetLocalPrefAction struct {
 	pref uint32
 }
 
-func NewSetLocalPrefAction(pref uint32) filter.FilterAction {
-	return &setLocalPrefAction{
+func NewSetLocalPrefAction(pref uint32) *SetLocalPrefAction {
+	return &SetLocalPrefAction{
 		pref: pref,
 	}
 }
 
-func (a *setLocalPrefAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
+func (a *SetLocalPrefAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
 	if pa.BGPPath == nil {
 		return pa, false
 	}
diff --git a/routingtable/filter/actions/set_nexthop_action.go b/routingtable/filter/actions/set_nexthop_action.go
index 41200a84..f178f618 100644
--- a/routingtable/filter/actions/set_nexthop_action.go
+++ b/routingtable/filter/actions/set_nexthop_action.go
@@ -3,26 +3,25 @@ package actions
 import (
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/route"
-	"github.com/bio-routing/bio-rd/routingtable/filter"
 )
 
-type setNextHopAction struct {
+type SetNextHopAction struct {
 	addr uint32
 }
 
-func NewSetNextHopAction(addr uint32) filter.FilterAction {
-	return &setNextHopAction{
+func NewSetNextHopAction(addr uint32) *SetNextHopAction {
+	return &SetNextHopAction{
 		addr: addr,
 	}
 }
 
-func (a *setNextHopAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
+func (a *SetNextHopAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
 	if pa.BGPPath == nil {
 		return pa, false
 	}
 
-	modified := *pa
+	modified := pa.Copy()
 	modified.BGPPath.NextHop = a.addr
 
-	return &modified, false
+	return modified, false
 }
-- 
GitLab