diff --git a/config/peer.go b/config/peer.go
index 9e057b9da60f6a33632a55bf7a3181c4a850ba70..ded26d7bd89f5d3bde535148284c632cfef14284 100644
--- a/config/peer.go
+++ b/config/peer.go
@@ -3,19 +3,22 @@ package config
 import (
 	"net"
 
+	"time"
+
 	"github.com/bio-routing/bio-rd/routingtable"
 )
 
 type Peer struct {
-	AdminEnabled bool
-	KeepAlive    uint16
-	HoldTimer    uint16
-	LocalAddress net.IP
-	PeerAddress  net.IP
-	LocalAS      uint32
-	PeerAS       uint32
-	Passive      bool
-	RouterID     uint32
-	AddPathSend  routingtable.ClientOptions
-	AddPathRecv  bool
+	AdminEnabled      bool
+	KeepAlive         uint16
+	HoldTimer         uint16
+	LocalAddress      net.IP
+	PeerAddress       net.IP
+	LocalAS           uint32
+	PeerAS            uint32
+	Passive           bool
+	RouterID          uint32
+	AddPathSend       routingtable.ClientOptions
+	AddPathRecv       bool
+	ReconnectInterval time.Duration
 }
diff --git a/main.go b/main.go
index 29c4b0d418f890d0778b3b9001bcfea95a690cfe..1952d771d9713831e851f7c7388b532ba1f4f7f1 100644
--- a/main.go
+++ b/main.go
@@ -15,7 +15,7 @@ import (
 )
 
 func main() {
-	fmt.Printf("This is a BGP speaker\n")
+	logrus.Printf("This is a BGP speaker\n")
 
 	rib := locRIB.New()
 	b := server.NewBgpServer()
diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go
index 71c4236b18f515a2f07d65ebaa829edebb3dcba2..307c34ab118a6d56072daa282753b6c220e7d908 100644
--- a/protocols/bgp/packet/bgp.go
+++ b/protocols/bgp/packet/bgp.go
@@ -51,6 +51,10 @@ const (
 	InvalidNetworkField       = 10
 	MalformedASPath           = 11
 
+	// Notification Msg Subcodes
+	AdministrativeShutdown = 2
+	AdministrativeReset    = 4
+
 	// Attribute Type Codes
 	OriginAttr         = 1
 	ASPathAttr         = 2
@@ -59,6 +63,9 @@ const (
 	LocalPrefAttr      = 5
 	AtomicAggrAttr     = 6
 	AggregatorAttr     = 7
+	CommunitiesAttr = 8
+	AS4PathAttr       = 17
+	AS4AggregatorAttr = 18
 	LargeCommunityAttr = 32
 
 	// ORIGIN values
diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go
index 961789b3cfdd43b0aae606e2a693ceef88a315b9..31583bf1b68257625dfaa3d8b8e40893982d6713 100644
--- a/protocols/bgp/packet/decoder.go
+++ b/protocols/bgp/packet/decoder.go
@@ -114,7 +114,7 @@ func decodeNotificationMsg(buf *bytes.Buffer) (*BGPNotification, error) {
 			return invalidErrCode(msg)
 		}
 	case Cease:
-		if msg.ErrorSubcode != 0 {
+		if !(msg.ErrorSubcode == 0 || msg.ErrorSubcode == AdministrativeShutdown || msg.ErrorSubcode == AdministrativeReset) {
 			return invalidErrCode(msg)
 		}
 	default:
diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go
index 4cbc8c110b507ce475c7b7f22ac3d73ba43992f1..19a83a960c956378415d2c1792abce344dbb76dc 100644
--- a/protocols/bgp/packet/decoder_test.go
+++ b/protocols/bgp/packet/decoder_test.go
@@ -651,7 +651,6 @@ func TestDecodeUpdateMsg(t *testing.T) {
 				3,              // Attribute Type code (Next Hop)
 				4,              // Length
 				10, 11, 12, 13, // Next Hop
-
 			},
 			wantFail: false,
 			expected: &BGPUpdate{
@@ -745,7 +744,6 @@ func TestDecodeUpdateMsg(t *testing.T) {
 				4,          // Attribute Type code (Next Hop)
 				4,          // Length
 				0, 0, 1, 0, // MED 256
-
 			},
 			wantFail: false,
 			expected: &BGPUpdate{
@@ -1242,6 +1240,191 @@ func TestDecodeUpdateMsg(t *testing.T) {
 			explicitLength: 5,
 			wantFail:       true,
 		},
+		{
+			// Unknown attribute
+			testNum: 16,
+			input: []byte{
+				0, 0, // No Withdraws
+				0, 7, // Total Path Attributes Length
+				64, 111, 4, 1, 1, 1, 1, // Unknown attribute
+			},
+			wantFail: false,
+			expected: &BGPUpdate{
+				TotalPathAttrLen: 7,
+				PathAttributes: &PathAttribute{
+					Length:     4,
+					Transitive: true,
+					TypeCode:   111,
+					Value:      []byte{1, 1, 1, 1},
+				},
+			},
+		},
+		{
+			// 2 withdraws with two path attributes (Communities + Origin), valid update
+			testNum: 17,
+			input: []byte{0, 5, 8, 10, 16, 192, 168,
+				0, 16, // Total Path Attribute Length
+
+				0,          // Attribute flags
+				8,          // Attribute Type code (Community)
+				8,          // Length
+				0, 0, 1, 0, // Arbitrary Community
+				0, 0, 1, 1, // Arbitrary Community
+
+				255,  // Attribute flags
+				1,    // Attribute Type code (ORIGIN)
+				0, 1, // Length
+				2, // INCOMPLETE
+
+			},
+			wantFail: false,
+			expected: &BGPUpdate{
+				WithdrawnRoutesLen: 5,
+				WithdrawnRoutes: &NLRI{
+					IP:     strAddr("10.0.0.0"),
+					Pfxlen: 8,
+					Next: &NLRI{
+						IP:     strAddr("192.168.0.0"),
+						Pfxlen: 16,
+					},
+				},
+				TotalPathAttrLen: 16,
+				PathAttributes: &PathAttribute{
+					Optional:       false,
+					Transitive:     false,
+					Partial:        false,
+					ExtendedLength: false,
+					Length:         8,
+					TypeCode:       8,
+					Value:          []uint32{256, 257},
+					Next: &PathAttribute{
+						Optional:       true,
+						Transitive:     true,
+						Partial:        true,
+						ExtendedLength: true,
+						Length:         1,
+						TypeCode:       1,
+						Value:          uint8(2),
+					},
+				},
+			},
+		},
+		{
+			// 2 withdraws with two path attributes (ORIGIN + Community), invalid update (too short community)
+			testNum: 18,
+			input: []byte{0, 5, 8, 10, 16, 192, 168,
+				0, 11, // Total Path Attribute Length
+
+				255,  // Attribute flags
+				1,    // Attribute Type code (ORIGIN)
+				0, 1, // Length
+				2, // INCOMPLETE
+
+				0,       // Attribute flags
+				8,       // Attribute Type code (Community)
+				3,       // Length
+				0, 0, 1, // Arbitrary Community
+			},
+			wantFail: true,
+			expected: nil,
+		},
+		{
+			// 2 withdraws with two path attributes (ORIGIN + Community), invalid update (too long community)
+			testNum: 19,
+			input: []byte{0, 5, 8, 10, 16, 192, 168,
+				0, 13, // Total Path Attribute Length
+
+				255,  // Attribute flags
+				1,    // Attribute Type code (ORIGIN)
+				0, 1, // Length
+				2, // INCOMPLETE
+
+				0,             // Attribute flags
+				8,             // Attribute Type code (Community)
+				5,             // Length
+				0, 0, 1, 0, 1, // Arbitrary Community
+			},
+			wantFail: true,
+			expected: nil,
+		},
+		{
+			// 2 withdraws with four path attributes (Communities + AS4Path +AS4Aggregator + Origin), valid update
+			testNum: 19,
+			input: []byte{0, 5, 8, 10, 16, 192, 168,
+				0, 30, // Total Path Attribute Length
+
+				0,          // Attribute flags
+				8,          // Attribute Type code (Community)
+				8,          // Length
+				0, 0, 1, 0, // Arbitrary Community
+				0, 0, 1, 1, // Arbitrary Community
+
+				128,        // Attribute flags
+				17,         // Attribute Type code (AS4Path)
+				4,          // Length
+				0, 0, 2, 3, // Arbitrary Bytes
+
+				128,        // Attribute flags
+				18,         // Attribute Type code (AS4Aggregator)
+				4,          // Length
+				0, 0, 2, 3, // Arbitrary Bytes
+
+				255,  // Attribute flags
+				1,    // Attribute Type code (ORIGIN)
+				0, 1, // Length
+				2, // INCOMPLETE
+
+			},
+			wantFail: false,
+			expected: &BGPUpdate{
+				WithdrawnRoutesLen: 5,
+				WithdrawnRoutes: &NLRI{
+					IP:     strAddr("10.0.0.0"),
+					Pfxlen: 8,
+					Next: &NLRI{
+						IP:     strAddr("192.168.0.0"),
+						Pfxlen: 16,
+					},
+				},
+				TotalPathAttrLen: 30,
+				PathAttributes: &PathAttribute{
+					Optional:       false,
+					Transitive:     false,
+					Partial:        false,
+					ExtendedLength: false,
+					Length:         8,
+					TypeCode:       8,
+					Value:          []uint32{256, 257},
+					Next: &PathAttribute{
+						Optional:       true,
+						Transitive:     false,
+						Partial:        false,
+						ExtendedLength: false,
+						Length:         4,
+						TypeCode:       17,
+						Value:          uint32(515),
+						Next: &PathAttribute{
+							Optional:       true,
+							Transitive:     false,
+							Partial:        false,
+							ExtendedLength: false,
+							Length:         4,
+							TypeCode:       18,
+							Value:          uint32(515),
+							Next: &PathAttribute{
+								Optional:       true,
+								Transitive:     true,
+								Partial:        true,
+								ExtendedLength: true,
+								Length:         1,
+								TypeCode:       1,
+								Value:          uint8(2),
+							},
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for _, test := range tests {
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index d9b5aa0cae45f4f1079536e17ddf6f4d75dd387c..055a85e244cefbd101e9b41465e095d935d35e8d 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -84,17 +84,46 @@ func decodePathAttr(buf *bytes.Buffer) (pa *PathAttribute, consumed uint16, err
 		}
 	case AtomicAggrAttr:
 		// Nothing to do for 0 octet long attribute
+	case CommunitiesAttr:
+		if err := pa.decodeCommunities(buf); err != nil {
+			return nil, consumed, fmt.Errorf("Failed to decode Community: %v", err)
+		}
+	case AS4PathAttr:
+		if err := pa.decodeAS4Path(buf); err != nil {
+			return nil, consumed, fmt.Errorf("Failed to skip not supported AS4Path: %v", err)
+		}
+	case AS4AggregatorAttr:
+		if err := pa.decodeAS4Aggregator(buf); err != nil {
+			return nil, consumed, fmt.Errorf("Failed to skip not supported AS4Aggregator: %v", err)
+		}
 	case LargeCommunityAttr:
 		if err := pa.decodeLargeCommunities(buf); err != nil {
 			return nil, consumed, fmt.Errorf("Failed to decode large communities: %v", err)
 		}
 	default:
-		return nil, consumed, fmt.Errorf("Invalid Attribute Type Code: %v", pa.TypeCode)
+		if err := pa.decodeUnknown(buf); err != nil {
+			return nil, consumed, fmt.Errorf("Failed to decode unknown attribute: %v", err)
+		}
 	}
 
 	return pa, consumed + pa.Length, nil
 }
 
+func (pa *PathAttribute) decodeUnknown(buf *bytes.Buffer) error {
+	u := make([]byte, pa.Length)
+
+	p := uint16(0)
+	err := decode(buf, []interface{}{&u})
+	if err != nil {
+		return fmt.Errorf("Unable to decode: %v", err)
+	}
+
+	pa.Value = u
+	p += pa.Length
+
+	return nil
+}
+
 func (pa *PathAttribute) decodeOrigin(buf *bytes.Buffer) error {
 	origin := uint8(0)
 
@@ -214,6 +243,27 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error {
 	return dumpNBytes(buf, pa.Length-p)
 }
 
+func (pa *PathAttribute) decodeCommunities(buf *bytes.Buffer) error {
+	if pa.Length%4 != 0 {
+		return fmt.Errorf("Unable to read community path attribute length %d is not divisible by 4", pa.Length)
+	}
+	comNumber := pa.Length / 4
+	var com = make([]uint32, comNumber)
+	for i := uint16(0); i < comNumber; i++ {
+		c := [4]byte{}
+		n, err := buf.Read(c[:])
+		if err != nil {
+			return err
+		}
+		if n != 4 {
+			return fmt.Errorf("Unable to read next hop: buf.Read read %d bytes", n)
+		}
+		com[i] = fourBytesToUint32(c)
+	}
+	pa.Value = com
+	return nil
+}
+
 func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
 	length := pa.Length
 	count := length / LargeCommunityLen
@@ -250,6 +300,26 @@ func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
 	return dumpNBytes(buf, dump)
 }
 
+func (pa *PathAttribute) decodeAS4Path(buf *bytes.Buffer) error {
+	as4Path, err := pa.decodeUint32(buf)
+	if err != nil {
+		return fmt.Errorf("Unable to decode AS4Path: %v", err)
+	}
+
+	pa.Value = as4Path
+	return nil
+}
+
+func (pa *PathAttribute) decodeAS4Aggregator(buf *bytes.Buffer) error {
+	as4Aggregator, err := pa.decodeUint32(buf)
+	if err != nil {
+		return fmt.Errorf("Unable to decode AS4Aggregator: %v", err)
+	}
+
+	pa.Value = as4Aggregator
+	return nil
+}
+
 func (pa *PathAttribute) setLength(buf *bytes.Buffer) (int, error) {
 	bytesRead := 0
 	if pa.ExtendedLength {
@@ -527,6 +597,10 @@ func ParseASPathStr(asPathString string) (*PathAttribute, error) {
 	newSegmentNeeded := true
 	currentSegment := -1
 	for _, asn := range strings.Split(asPathString, " ") {
+		if asn == "" {
+			continue
+		}
+
 		if isBeginOfASSet(asn) {
 			currentType = ASSet
 			newSegmentNeeded = true
diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index a56fba0d237d26128af87c500e12a62bb11217b7..0e049760ae3a08b9540bef33906a072dfc29e187 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -1456,6 +1456,15 @@ func TestParseASPathStr(t *testing.T) {
 		wantFail bool
 		expected *PathAttribute
 	}{
+		{
+			name:     "Empty AS Path",
+			input:    "",
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ASPathAttr,
+				Value:    ASPath{},
+			},
+		},
 		{
 			name:     "Simple AS_SEQUENCE",
 			input:    "3320 15169",
diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go
index d4c472066583d2c0190b64ef60b98f54a61b981e..1a20503e13c9057fa5ed454150d422dd0faa9774 100644
--- a/protocols/bgp/server/fsm.go
+++ b/protocols/bgp/server/fsm.go
@@ -16,7 +16,6 @@ import (
 	"github.com/bio-routing/bio-rd/routingtable/adjRIBIn"
 	"github.com/bio-routing/bio-rd/routingtable/adjRIBOut"
 	"github.com/bio-routing/bio-rd/routingtable/adjRIBOutAddPath"
-	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 	log "github.com/sirupsen/logrus"
 	tomb "gopkg.in/tomb.v2"
 )
@@ -84,7 +83,7 @@ type FSM struct {
 	holdTimer          *time.Timer
 
 	keepaliveTime  time.Duration
-	keepaliveTimer *time.Timer
+	keepaliveTimer *time.Ticker
 
 	msgRecvCh     chan msgRecvMsg
 	msgRecvFailCh chan msgRecvErr
@@ -92,7 +91,7 @@ type FSM struct {
 
 	adjRIBIn     *adjRIBIn.AdjRIBIn
 	adjRIBOut    routingtable.RouteTableClient
-	rib          *locRIB.LocRIB
+	rib          routingtable.RouteTableClient
 	updateSender routingtable.RouteTableClient
 
 	capAddPathSend bool
@@ -109,7 +108,7 @@ type msgRecvErr struct {
 	con *net.TCPConn
 }
 
-func NewFSM(peer *Peer, c config.Peer, rib *locRIB.LocRIB) *FSM {
+func NewFSM(peer *Peer, c config.Peer, rib routingtable.RouteTableClient) *FSM {
 	fsm := &FSM{
 		peer:              peer,
 		state:             Idle,
@@ -125,7 +124,7 @@ func NewFSM(peer *Peer, c config.Peer, rib *locRIB.LocRIB) *FSM {
 		holdTimer:          time.NewTimer(0),
 
 		keepaliveTime:  time.Duration(c.KeepAlive),
-		keepaliveTimer: time.NewTimer(0),
+		keepaliveTimer: time.NewTicker(time.Duration(c.KeepAlive)),
 
 		routerID: c.RouterID,
 		remote:   c.PeerAddress,
@@ -458,7 +457,10 @@ func (fsm *FSM) openSent() int {
 				if fsm.holdTime != 0 {
 					fsm.holdTimer.Reset(time.Second * fsm.holdTime)
 					fsm.keepaliveTime = fsm.holdTime / 3
-					fsm.keepaliveTimer.Reset(time.Second * fsm.keepaliveTime)
+					if fsm.keepaliveTimer != nil {
+						fsm.keepaliveTimer.Stop()
+					}
+					fsm.keepaliveTimer = time.NewTicker(fsm.keepaliveTime * time.Second)
 				}
 
 				fsm.processOpenOptions(openMsg.OptParams)
@@ -624,7 +626,6 @@ func (fsm *FSM) openConfirm() int {
 				fsm.connectRetryCounter++
 				return fsm.changeState(Idle, fmt.Sprintf("Failed to send keepalive: %v", err))
 			}
-			fsm.keepaliveTimer.Reset(time.Second * fsm.keepaliveTime)
 			continue
 		case c := <-fsm.conCh:
 			if fsm.con2 != nil {
@@ -647,7 +648,7 @@ func (fsm *FSM) openConfirm() int {
 		case recvMsg := <-fsm.msgRecvCh:
 			msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg))
 			if err != nil {
-				fmt.Printf("Failed to decode message: %v\n", recvMsg.msg)
+				log.WithError(err).Errorf("Failed to decode BGP message %v\n", recvMsg.msg)
 				switch bgperr := err.(type) {
 				case packet.BGPError:
 					sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode)
@@ -751,6 +752,7 @@ func (fsm *FSM) established() int {
 	}()*/
 
 	for {
+		log.Debug("Iterate established loop.")
 		select {
 		case e := <-fsm.eventCh:
 			if e == ManualStop { // Event 2
@@ -775,6 +777,7 @@ func (fsm *FSM) established() int {
 			fsm.connectRetryCounter++
 			return fsm.changeState(Idle, "Holdtimer expired")
 		case <-fsm.keepaliveTimer.C:
+
 			err := fsm.sendKeepalive()
 			if err != nil {
 				stopTimer(fsm.connectRetryTimer)
@@ -782,7 +785,6 @@ func (fsm *FSM) established() int {
 				fsm.connectRetryCounter++
 				return fsm.changeState(Idle, fmt.Sprintf("Failed to send keepalive: %v", err))
 			}
-			fsm.keepaliveTimer.Reset(time.Second * fsm.keepaliveTime)
 			continue
 		case c := <-fsm.conCh:
 			c.Close()
@@ -790,7 +792,7 @@ func (fsm *FSM) established() int {
 		case recvMsg := <-fsm.msgRecvCh:
 			msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg))
 			if err != nil {
-				fmt.Printf("Failed to decode BGP message: %v\n", recvMsg.msg)
+        log.WithError(err).Errorf("Failed to decode BGP message %v\n", recvMsg.msg)
 				switch bgperr := err.(type) {
 				case packet.BGPError:
 					sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode)
@@ -815,14 +817,13 @@ func (fsm *FSM) established() int {
 
 				for r := u.WithdrawnRoutes; r != nil; r = r.Next {
 					pfx := tnet.NewPfx(r.IP, r.Pfxlen)
-					fmt.Printf("LPM: Removing prefix %s\n", pfx.String())
+					log.WithField("Prefix", pfx.String()).Debug("LPM: Removing prefix")
 					fsm.adjRIBIn.RemovePath(pfx, nil)
 				}
 
 				for r := u.NLRI; r != nil; r = r.Next {
 					pfx := tnet.NewPfx(r.IP, r.Pfxlen)
-					fmt.Printf("LPM: Adding prefix %s\n", pfx.String())
-
+					log.WithField("Prefix", pfx.String()).Debug("LPM: Adding prefix")
 					path := &route.Path{
 						Type: route.BGPPathType,
 						BGPPath: &route.BGPPath{
@@ -831,7 +832,6 @@ func (fsm *FSM) established() int {
 					}
 
 					for pa := u.PathAttributes; pa != nil; pa = pa.Next {
-						fmt.Printf("TypeCode: %d\n", pa.TypeCode)
 						switch pa.TypeCode {
 						case packet.OriginAttr:
 							path.BGPPath.Origin = pa.Value.(uint8)
@@ -840,7 +840,7 @@ func (fsm *FSM) established() int {
 						case packet.MEDAttr:
 							path.BGPPath.MED = pa.Value.(uint32)
 						case packet.NextHopAttr:
-							fmt.Printf("RECEIVED NEXT_HOP: %d\n", pa.Value.(uint32))
+							log.WithField("NextHop", pa.Value.(uint32)).Debug("RECEIVED NEXT_HOP")
 							path.BGPPath.NextHop = pa.Value.(uint32)
 						case packet.ASPathAttr:
 							path.BGPPath.ASPath = pa.ASPathString()
@@ -921,9 +921,10 @@ func (fsm *FSM) resetDelayOpenTimer() {
 }
 
 func (fsm *FSM) sendKeepalive() error {
-	msg := packet.SerializeKeepaliveMsg()
 
+	msg := packet.SerializeKeepaliveMsg()
 	_, err := fsm.con.Write(msg)
+	log.WithError(err).Debug("Send keepalive")
 	if err != nil {
 		return fmt.Errorf("Unable to send KEEPALIVE message: %v", err)
 	}
diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go
index 7bfcbc560181663fec221f76ada98d00ef29e517..5077aaeff37e7634f0e2d12bb4988d30f1f52775 100644
--- a/protocols/bgp/server/peer.go
+++ b/protocols/bgp/server/peer.go
@@ -3,32 +3,36 @@ package server
 import (
 	"net"
 
+	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/routingtable"
-	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 
-	"github.com/bio-routing/bio-rd/config"
+	"time"
 )
 
 type Peer struct {
-	addr          net.IP
-	asn           uint32
-	fsm           *FSM
-	rib           *locRIB.LocRIB
-	routerID      uint32
-	addPathSend   routingtable.ClientOptions
-	addPathRecv   bool
-	optOpenParams []packet.OptParam
+	addr              net.IP
+	asn               uint32
+	fsm               *FSM
+	rib               routingtable.RouteTableClient
+	routerID          uint32
+	addPathSend       routingtable.ClientOptions
+	addPathRecv       bool
+	optOpenParams     []packet.OptParam
+	reconnectInterval time.Duration
 }
 
-func NewPeer(c config.Peer, rib *locRIB.LocRIB) (*Peer, error) {
+// NewPeer creates a new peer with the given config. If an connection is established, the adjRIBIN of the peer is connected
+// to the given rib. To actually connect the peer, call Start() on the returned peer.
+func NewPeer(c config.Peer, rib routingtable.RouteTableClient) (*Peer, error) {
 	p := &Peer{
-		addr:          c.PeerAddress,
-		asn:           c.PeerAS,
-		rib:           rib,
-		addPathSend:   c.AddPathSend,
-		addPathRecv:   c.AddPathRecv,
-		optOpenParams: make([]packet.OptParam, 0),
+		addr:              c.PeerAddress,
+		asn:               c.PeerAS,
+		rib:               rib,
+		addPathSend:       c.AddPathSend,
+		addPathRecv:       c.AddPathRecv,
+		optOpenParams:     make([]packet.OptParam, 0),
+		reconnectInterval: c.ReconnectInterval,
 	}
 	p.fsm = NewFSM(p, c, rib)
 
@@ -63,15 +67,29 @@ func NewPeer(c config.Peer, rib *locRIB.LocRIB) (*Peer, error) {
 	return p, nil
 }
 
+// GetAddr returns the IP address of the peer
 func (p *Peer) GetAddr() net.IP {
 	return p.addr
 }
 
+// GetASN returns the configured AS number of the peer
 func (p *Peer) GetASN() uint32 {
 	return p.asn
 }
 
+// Start the peers fsm. It starts from the Idle state and will get an ManualStart event. To trigger
+// reconnects if the fsm falls back into the Idle state, every reconnectInterval a ManualStart event is send.
+// The default value for reconnectInterval is 30 seconds.
 func (p *Peer) Start() {
 	p.fsm.start()
-	p.fsm.activate()
+	if p.reconnectInterval == 0 {
+		p.reconnectInterval = 30 * time.Second
+	}
+	t := time.Tick(p.reconnectInterval)
+	go func() {
+		for {
+			<-t
+			p.fsm.activate()
+		}
+	}()
 }
diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go
index 8a11cd3a0641c6ff926ddc4459da157d7273db44..a6025140fd62f81d8fa503aeb0c31114a7589f2b 100644
--- a/protocols/bgp/server/server.go
+++ b/protocols/bgp/server/server.go
@@ -8,7 +8,7 @@ import (
 
 	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/bio-routing/bio-rd/routingtable"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -39,7 +39,7 @@ func (b *BGPServer) Start(c *config.Global) error {
 		return fmt.Errorf("Failed to load defaults: %v", err)
 	}
 
-	fmt.Printf("ROUTER ID: %d\n", c.RouterID)
+	log.Infof("ROUTER ID: %d\n", c.RouterID)
 	b.routerID = c.RouterID
 
 	if c.Listen {
@@ -62,8 +62,6 @@ func (b *BGPServer) Start(c *config.Global) error {
 func (b *BGPServer) incomingConnectionWorker() {
 	for {
 		c := <-b.acceptCh
-		fmt.Printf("Incoming connection!\n")
-		fmt.Printf("Connection from: %v\n", c.RemoteAddr())
 
 		peerAddr := strings.Split(c.RemoteAddr().String(), ":")[0]
 		if _, ok := b.peers[peerAddr]; !ok {
@@ -78,13 +76,13 @@ func (b *BGPServer) incomingConnectionWorker() {
 			"source": c.RemoteAddr(),
 		}).Info("Incoming TCP connection")
 
-		fmt.Printf("DEBUG: Sending incoming TCP connection to fsm for peer %s\n", peerAddr)
+		log.WithField("Peer", peerAddr).Debug("Sending incoming TCP connection to fsm for peer")
 		b.peers[peerAddr].fsm.conCh <- c
-		fmt.Printf("DEBUG: Sending done\n")
+		log.Debug("Sending done")
 	}
 }
 
-func (b *BGPServer) AddPeer(c config.Peer, rib *locRIB.LocRIB) error {
+func (b *BGPServer) AddPeer(c config.Peer, rib routingtable.RouteTableClient) error {
 	if c.LocalAS > uint16max || c.PeerAS > uint16max {
 		return fmt.Errorf("32bit ASNs are not supported yet")
 	}
diff --git a/protocols/bgp/server/bgp_update.go b/protocols/bgp/server/update_helper.go
similarity index 74%
rename from protocols/bgp/server/bgp_update.go
rename to protocols/bgp/server/update_helper.go
index 28018bf102a420b49b513f057765a50ad7890e52..22bfeec52ad72e603583452c9bc9f70be314f4a7 100644
--- a/protocols/bgp/server/bgp_update.go
+++ b/protocols/bgp/server/update_helper.go
@@ -4,26 +4,10 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/route"
 )
 
-func updateMessageForPath(pfx net.Prefix, p *route.Path, fsm *FSM) (*packet.BGPUpdate, error) {
-	pathAttrs, err := pathAttribues(p, fsm)
-	if err != nil {
-		return nil, err
-	}
-
-	return &packet.BGPUpdate{
-		PathAttributes: pathAttrs,
-		NLRI: &packet.NLRI{
-			IP:     pfx.Addr(),
-			Pfxlen: pfx.Pfxlen(),
-		},
-	}, nil
-}
-
 func pathAttribues(p *route.Path, fsm *FSM) (*packet.PathAttribute, error) {
 	asPathPA, err := packet.ParseASPathStr(strings.TrimRight(fmt.Sprintf("%d %s", fsm.localASN, p.BGPPath.ASPath), " "))
 	if err != nil {
@@ -42,8 +26,14 @@ func pathAttribues(p *route.Path, fsm *FSM) (*packet.PathAttribute, error) {
 	}
 	asPathPA.Next = nextHop
 
+	localPref := &packet.PathAttribute{
+		TypeCode: packet.LocalPrefAttr,
+		Value:    p.BGPPath.LocalPref,
+	}
+	nextHop.Next = localPref
+
 	if p.BGPPath != nil {
-		err := addOptionalPathAttribues(p, nextHop)
+		err := addOptionalPathAttribues(p, localPref)
 
 		if err != nil {
 			return nil, err
diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go
index 4a514ec4c5529c10846124ca2c4371a1022e40e6..54c1d1b0cfa28c9094015d50483af1fd12bfd2e6 100644
--- a/protocols/bgp/server/update_sender.go
+++ b/protocols/bgp/server/update_sender.go
@@ -2,10 +2,12 @@ package server
 
 import (
 	"fmt"
+	"strings"
 
 	log "github.com/sirupsen/logrus"
 
 	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 )
@@ -13,23 +15,34 @@ import (
 // UpdateSender converts table changes into BGP update messages
 type UpdateSender struct {
 	routingtable.ClientManager
-	fsm *FSM
+	fsm  *FSM
+	iBGP bool
 }
 
 func newUpdateSender(fsm *FSM) *UpdateSender {
 	return &UpdateSender{
-		fsm: fsm,
+		fsm:  fsm,
+		iBGP: fsm.localASN == fsm.remoteASN,
 	}
 }
 
 // AddPath serializes a new path and sends out a BGP update message
 func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error {
-	update, err := updateMessageForPath(pfx, p, u.fsm)
+	pathAttrs, err := pathAttribues(p, u.fsm)
 	if err != nil {
 		log.Errorf("Unable to create BGP Update: %v", err)
 		return nil
 	}
 
+	update := &packet.BGPUpdateAddPath{
+		PathAttributes: pathAttrs,
+		NLRI: &packet.NLRIAddPath{
+			PathIdentifier: p.BGPPath.PathIdentifier,
+			IP:             pfx.Addr(),
+			Pfxlen:         pfx.Pfxlen(),
+		},
+	}
+
 	updateBytes, err := update.SerializeUpdate()
 	if err != nil {
 		log.Errorf("Unable to serialize BGP Update: %v", err)
@@ -54,3 +67,12 @@ func (u *UpdateSender) UpdateNewClient(client routingtable.RouteTableClient) err
 	log.Warningf("BGP Update Sender: UpdateNewClient() not supported")
 	return nil
 }
+
+func asPathString(iBGP bool, localASN uint16, asPath string) string {
+	ret := ""
+	if iBGP {
+		ret = ret + fmt.Sprintf("%d ", localASN)
+	}
+	ret = ret + asPath
+	return strings.TrimRight(ret, " ")
+}
diff --git a/protocols/bgp/server/update_sender_add_path.go b/protocols/bgp/server/update_sender_add_path.go
index f7c51c569953946b7a290ce1c5facc7c2c2b48ae..84d6796046b8b3380a6afae2f7ab1257b59a699c 100644
--- a/protocols/bgp/server/update_sender_add_path.go
+++ b/protocols/bgp/server/update_sender_add_path.go
@@ -6,6 +6,7 @@ import (
 	log "github.com/sirupsen/logrus"
 
 	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 )
@@ -13,23 +14,33 @@ import (
 // UpdateSenderAddPath converts table changes into BGP update messages with add path
 type UpdateSenderAddPath struct {
 	routingtable.ClientManager
-	fsm *FSM
+	fsm  *FSM
+	iBGP bool
 }
 
 func newUpdateSenderAddPath(fsm *FSM) *UpdateSenderAddPath {
 	return &UpdateSenderAddPath{
-		fsm: fsm,
+		fsm:  fsm,
+		iBGP: fsm.localASN == fsm.remoteASN,
 	}
 }
 
 // AddPath serializes a new path and sends out a BGP update message
 func (u *UpdateSenderAddPath) AddPath(pfx net.Prefix, p *route.Path) error {
-	update, err := updateMessageForPath(pfx, p, u.fsm)
+	pathAttrs, err := pathAttribues(p, u.fsm)
 	if err != nil {
 		log.Errorf("Unable to create BGP Update: %v", err)
 		return nil
 	}
 
+	update := &packet.BGPUpdate{
+		PathAttributes: pathAttrs,
+		NLRI: &packet.NLRI{
+			IP:     pfx.Addr(),
+			Pfxlen: pfx.Pfxlen(),
+		},
+	}
+
 	updateBytes, err := update.SerializeUpdate()
 	if err != nil {
 		log.Errorf("Unable to serialize BGP Update: %v", err)
diff --git a/route/bgp.go b/route/bgp.go
index 1109a42d2b8ee12cd4d1b7719ee402109b33085f..a19c4cde94873f5761fd579737bacde3fd240729 100644
--- a/route/bgp.go
+++ b/route/bgp.go
@@ -78,6 +78,14 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 		return -1
 	}
 
+	if c.NextHop < b.NextHop {
+		return 1
+	}
+
+	if c.NextHop > b.NextHop {
+		return -1
+	}
+
 	return 0
 }
 
@@ -133,10 +141,6 @@ func (b *BGPPath) better(c *BGPPath) bool {
 	return false
 }
 
-func (b *BGPPath) ecmp(c *BGPPath) bool {
-	return b.LocalPref == c.LocalPref && b.ASPathLen == c.ASPathLen && b.Origin == c.Origin && b.MED == c.MED
-}
-
 func (b *BGPPath) Print() string {
 	origin := ""
 	switch b.Origin {
diff --git a/routingtable/adjRIBIn/adj_rib_in.go b/routingtable/adjRIBIn/adj_rib_in.go
index 1427278bbd5aa6c465c16bf2ac4e1462fd5a34d8..cd4dde58f17e42d9bf75433850dfa39bf2498fbf 100644
--- a/routingtable/adjRIBIn/adj_rib_in.go
+++ b/routingtable/adjRIBIn/adj_rib_in.go
@@ -6,6 +6,7 @@ import (
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
+	log "github.com/sirupsen/logrus"
 )
 
 // AdjRIBIn represents an Adjacency RIB In as described in RFC4271
@@ -33,7 +34,11 @@ func (a *AdjRIBIn) UpdateNewClient(client routingtable.RouteTableClient) error {
 	for _, route := range routes {
 		paths := route.Paths()
 		for _, path := range paths {
-			client.AddPath(route.Prefix(), path)
+
+			err := client.AddPath(route.Prefix(), path)
+			if err != nil {
+				log.WithField("Sender", "AdjRIBOutAddPath").WithError(err).Error("Could not send update to client")
+			}
 		}
 	}
 	return nil
diff --git a/routingtable/adjRIBIn/adj_rib_in_test.go b/routingtable/adjRIBIn/adj_rib_in_test.go
index 5659ab805f73b3bf888a08fa8ff6a7dbe8185bdf..a994e0f5e82be4ccef141ce63463b762d055d111 100644
--- a/routingtable/adjRIBIn/adj_rib_in_test.go
+++ b/routingtable/adjRIBIn/adj_rib_in_test.go
@@ -34,6 +34,10 @@ func (m *RTMockClient) Register(routingtable.RouteTableClient) {
 	return
 }
 
+func (m *RTMockClient) RegisterWithOptions(routingtable.RouteTableClient, routingtable.ClientOptions) {
+	return
+}
+
 func (m *RTMockClient) Unregister(routingtable.RouteTableClient) {
 	return
 }
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index 1ddd93c6e05b835c9952b6e86ba5fe57545ed5e4..51347119a6b360fd2f81283edc18d9225548fdf2 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -7,6 +7,7 @@ import (
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
+	log "github.com/sirupsen/logrus"
 )
 
 // AdjRIBOut represents an Adjacency RIB In as described in RFC4271
@@ -45,7 +46,10 @@ func (a *AdjRIBOut) AddPath(pfx net.Prefix, p *route.Path) error {
 	a.removePathsFromClients(pfx, oldPaths)
 
 	for _, client := range a.ClientManager.Clients() {
-		client.AddPath(pfx, p)
+		err := client.AddPath(pfx, p)
+		if err != nil {
+			log.WithField("Sender", "AdjRIBOut").WithError(err).Error("Could not send update to client")
+		}
 	}
 	return nil
 }
diff --git a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go
index 2b4dff95575b2df72036642f40bd69cfedb4e5ab..90f76fcc873643a6d94086b0b84f5bf940b6fa9f 100644
--- a/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go
+++ b/routingtable/adjRIBOutAddPath/adj_rib_out_add_path.go
@@ -7,6 +7,7 @@ import (
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
+	log "github.com/sirupsen/logrus"
 )
 
 // AdjRIBOutAddPath represents an Adjacency RIB Out with BGP add path
@@ -52,7 +53,10 @@ func (a *AdjRIBOutAddPath) AddPath(pfx net.Prefix, p *route.Path) error {
 	a.rt.AddPath(pfx, p)
 
 	for _, client := range a.ClientManager.Clients() {
-		client.AddPath(pfx, p)
+		err := client.AddPath(pfx, p)
+		if err != nil {
+			log.WithField("Sender", "AdjRIBOutAddPath").WithError(err).Error("Could not send update to client")
+		}
 	}
 	return nil
 }
diff --git a/routingtable/client_interface.go b/routingtable/client_interface.go
index 0800ceec8db1cb3b758b74b3a1d3c8b7aef62acb..e7190c5b6c0bb1829f59cf5faadd0623ef3b395c 100644
--- a/routingtable/client_interface.go
+++ b/routingtable/client_interface.go
@@ -11,5 +11,6 @@ type RouteTableClient interface {
 	RemovePath(net.Prefix, *route.Path) bool
 	UpdateNewClient(RouteTableClient) error
 	Register(RouteTableClient)
+	RegisterWithOptions(RouteTableClient, ClientOptions)
 	Unregister(RouteTableClient)
 }
diff --git a/routingtable/client_manager.go b/routingtable/client_manager.go
index 20d848b2c090a4c311cb4a81fc8c1c4697cf5891..f29ae2dce47dc7e4a3d3ba725ff5d57fd27f74f6 100644
--- a/routingtable/client_manager.go
+++ b/routingtable/client_manager.go
@@ -55,9 +55,8 @@ func (c *ClientManager) Register(client RouteTableClient) {
 // RegisterWithOptions registers a client with options for updates
 func (c *ClientManager) RegisterWithOptions(client RouteTableClient, opt ClientOptions) {
 	c.mu.Lock()
-	defer c.mu.Unlock()
-
 	c.clients[client] = opt
+	c.mu.Unlock()
 	c.master.UpdateNewClient(client)
 }
 
diff --git a/routingtable/client_manager_test.go b/routingtable/client_manager_test.go
index af2507855bfac8a5d09551b105d7bfc4ae93dd79..78e2e58c4030a2e25a1b9ae228ef712fc1c67550 100644
--- a/routingtable/client_manager_test.go
+++ b/routingtable/client_manager_test.go
@@ -25,6 +25,11 @@ func (m MockClient) UpdateNewClient(RouteTableClient) error {
 func (m MockClient) Register(RouteTableClient) {
 	return
 }
+
+func (m MockClient) RegisterWithOptions(RouteTableClient, ClientOptions) {
+	return
+}
+
 func (m MockClient) Unregister(RouteTableClient) {
 	return
 }
diff --git a/routingtable/filter/term_condition.go b/routingtable/filter/term_condition.go
index 946a04e85781d160dd893dab84588a965ff9190e..003b9dcbc021e75cd28d3039efbad2d00bf1d109 100644
--- a/routingtable/filter/term_condition.go
+++ b/routingtable/filter/term_condition.go
@@ -11,6 +11,13 @@ type TermCondition struct {
 	largeCommunityFilters []*LargeCommunityFilter
 }
 
+func NewTermCondition(prefixLists []*PrefixList, routeFilters []*RouteFilter) *TermCondition {
+	return &TermCondition{
+		prefixLists:  prefixLists,
+		routeFilters: routeFilters,
+	}
+}
+
 func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool {
 	return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p) || f.machtchesAnyLageCommunityFilter(pa)
 }
diff --git a/routingtable/filter/term_condition_test.go b/routingtable/filter/term_condition_test.go
index 307cd5e0485d6388661c61c4f67cf1c2a4bdb9bd..6e9b89f20eb226faebdd3856fa4bc61a97388a4e 100644
--- a/routingtable/filter/term_condition_test.go
+++ b/routingtable/filter/term_condition_test.go
@@ -144,11 +144,8 @@ func TestMatches(t *testing.T) {
 
 	for _, test := range tests {
 		t.Run(test.name, func(te *testing.T) {
-			f := &TermCondition{
-				prefixLists:           test.prefixLists,
-				routeFilters:          test.routeFilters,
-				largeCommunityFilters: test.largeCommunityFilters,
-			}
+			f := NewTermCondition(test.prefixLists, test.routeFilters)
+			f.largeCommunityFilters = test.largeCommunityFilters
 
 			pa := &route.Path{
 				BGPPath: test.bgpPath,
diff --git a/routingtable/locRIB/loc_rib.go b/routingtable/locRIB/loc_rib.go
index 584954a954e394bf7f859693b87ec827529a4b05..ff5750c34d226080bea079968becdec410d2704e 100644
--- a/routingtable/locRIB/loc_rib.go
+++ b/routingtable/locRIB/loc_rib.go
@@ -8,6 +8,7 @@ import (
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/sirupsen/logrus"
 )
 
 // LocRIB represents a routing information base
@@ -44,6 +45,10 @@ func (a *LocRIB) AddPath(pfx net.Prefix, p *route.Path) error {
 	a.mu.Lock()
 	defer a.mu.Unlock()
 
+	logrus.WithFields(map[string]interface{}{
+		"Prefix": pfx,
+		"Route":  p,
+	}).Debug("AddPath to locRIB")
 	routeExisted := false
 	oldRoute := &route.Route{}
 	r := a.rt.Get(pfx)
@@ -70,10 +75,16 @@ func (a *LocRIB) RemovePath(pfx net.Prefix, p *route.Path) bool {
 	a.mu.Lock()
 	defer a.mu.Unlock()
 
+	logrus.WithFields(map[string]interface{}{
+		"Prefix": pfx,
+		"Route":  p,
+	}).Debug("Remove from locRIB")
 	var oldRoute *route.Route
 	r := a.rt.Get(pfx)
 	if r != nil {
 		oldRoute = r.Copy()
+	} else {
+		return true
 	}
 
 	a.rt.RemovePath(pfx, p)
diff --git a/routingtable/locRIB/loc_rib_test.go b/routingtable/locRIB/loc_rib_test.go
index 6493991c9c30a4df8352b4496f3fd953ad60a926..ea4d9c6c30e5596f4b0685d92a20b86eb182bf16 100644
--- a/routingtable/locRIB/loc_rib_test.go
+++ b/routingtable/locRIB/loc_rib_test.go
@@ -84,3 +84,14 @@ func TestContainsPfxPath(t *testing.T) {
 		assert.Equal(t, tc.expected, contains, "mismatch in testcase %v", i)
 	}
 }
+
+func TestLocRIB_RemovePathUnknown(t *testing.T) {
+	rib := New()
+	assert.True(t, rib.RemovePath(net.NewPfx(1, 32),
+		&route.Path{
+			Type: route.StaticPathType,
+			StaticPath: &route.StaticPath{
+				NextHop: 2,
+			},
+		}))
+}