diff --git a/route/bgp.go b/route/bgp.go
index 47f7db4fc15980936e174ffa540fd3c09bb04a7e..cde74bddecd79c022dc1f204ffb6a26b6879e2be 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 544b83b485c106870b8ff7a251539187c85a06d6..ef2e881798212232fc6e116d2df2764e7d6207d3 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 483138f04874ff7f50185ba3fcfb04fb007c6029..0ab6b26e3dc01c58b756efca28935b2e8e4e9d5a 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 0000000000000000000000000000000000000000..30d63ca783fd91a9530f336f3311106c57ac5968
--- /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 0000000000000000000000000000000000000000..7a2665146922719766b880f9093eb1049c6ae018
--- /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 1b59be48e16b844aae069c5795d7acc691e87612..e60b6faa0ab5e4e986f785d7b8322db2c6492e34 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 41200a845a6f4ba6c31f9e30e202971eca1be9cb..f178f61802882157856fc1f4bf15c8d9f0b08dc6 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
 }