diff --git a/AUTHORS b/AUTHORS
index e5550af433c7e0a9484e2dcc6864dfd4c143e3db..08ed97f577221522d6c0a274e2ebf58a988e5e67 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,6 +11,7 @@
 # Please keep the list sorted.
 
 Cedric Kienzler
+Christoph Petrausch
 Daniel Czerwonk
 Oliver Herms
-Christoph Petrausch
+Serge Bazanski
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index fcfb3b8f82816f64cc48ba60b973fad370be3f6a..50ab2c58221250b162b98ca4e6d6cdc0f0f7eaa4 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -5,6 +5,7 @@
 # but not in AUTHORS, because Google holds the copyright.
 
 Cedric Kienzler
+Christoph Petrausch
 Daniel Czerwonk
 Oliver Herms
-Christoph Petrausch
\ No newline at end of file
+Serge Bazanski
diff --git a/config/server.go b/config/server.go
index fed6f908365319418abb5b5dee1290ec666d418e..964f5be1097c48aaaaca6e064d7e048b67caedea 100644
--- a/config/server.go
+++ b/config/server.go
@@ -9,7 +9,7 @@ import (
 )
 
 type Global struct {
-	LocalAS          uint32
+	LocalASN         uint32
 	RouterID         uint32
 	Port             uint16
 	LocalAddressList []net.IP
diff --git a/main.go b/main.go
index e311932915a7f33c7135d45b804ca4ee429a1544..5ca73039c8a12c21bcb7a94f8497b7642b3eaaac 100644
--- a/main.go
+++ b/main.go
@@ -3,7 +3,6 @@ package main
 import (
 	"fmt"
 	"net"
-	"sync"
 	"time"
 
 	"github.com/sirupsen/logrus"
@@ -83,7 +82,5 @@ func main() {
 		}
 	}()
 
-	var wg sync.WaitGroup
-	wg.Add(1)
-	wg.Wait()
+	select {}
 }
diff --git a/protocols/bgp/server/BUILD.bazel b/protocols/bgp/server/BUILD.bazel
index e9ebd9630360ff10efb76e29efaf668dc227d3e8..66889d6c4a8b6fa885eb5281f419fe53cf6a5c31 100644
--- a/protocols/bgp/server/BUILD.bazel
+++ b/protocols/bgp/server/BUILD.bazel
@@ -41,6 +41,7 @@ go_library(
 go_test(
     name = "go_default_test",
     srcs = [
+        "server_test.go",
         "update_helper_test.go",
         "withdraw_test.go",
     ],
@@ -49,6 +50,7 @@ go_test(
         "//net:go_default_library",
         "//protocols/bgp/packet:go_default_library",
         "//route:go_default_library",
+        "//routingtable/locRIB:go_default_library",
         "//vendor/github.com/stretchr/testify/assert:go_default_library",
     ],
 )
diff --git a/protocols/bgp/server/fsm2.go b/protocols/bgp/server/fsm2.go
index 6e1682c71b7aaf47ff2858a30b199fc07cb43297..33e000d1c6010a2e3b976b13bec591a7e0e67545 100644
--- a/protocols/bgp/server/fsm2.go
+++ b/protocols/bgp/server/fsm2.go
@@ -28,7 +28,7 @@ type state interface {
 
 // FSM implements the BGP finite state machine (RFC4271)
 type FSM struct {
-	peer        *Peer
+	peer        *peer
 	eventCh     chan int
 	con         net.Conn
 	conCh       chan net.Conn
@@ -72,7 +72,7 @@ type FSM struct {
 }
 
 // NewPassiveFSM2 initiates a new passive FSM
-func NewPassiveFSM2(peer *Peer, con *net.TCPConn) *FSM {
+func NewPassiveFSM2(peer *peer, con *net.TCPConn) *FSM {
 	fsm := newFSM2(peer)
 	fsm.con = con
 	fsm.state = newIdleState(fsm)
@@ -80,14 +80,14 @@ func NewPassiveFSM2(peer *Peer, con *net.TCPConn) *FSM {
 }
 
 // NewActiveFSM2 initiates a new passive FSM
-func NewActiveFSM2(peer *Peer) *FSM {
+func NewActiveFSM2(peer *peer) *FSM {
 	fsm := newFSM2(peer)
 	fsm.active = true
 	fsm.state = newIdleState(fsm)
 	return fsm
 }
 
-func newFSM2(peer *Peer) *FSM {
+func newFSM2(peer *peer) *FSM {
 	return &FSM{
 		connectRetryTime: time.Minute,
 		peer:             peer,
diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go
index a0e4c623b5d4d30bdb877311c879b7c568332859..58f53bef65995eb08066e3f0987032a7e85aba7b 100644
--- a/protocols/bgp/server/peer.go
+++ b/protocols/bgp/server/peer.go
@@ -11,13 +11,22 @@ import (
 	"github.com/bio-routing/bio-rd/routingtable/filter"
 )
 
-type Peer struct {
-	server            *BGPServer
-	addr              net.IP
-	peerASN           uint32
-	localASN          uint32
-	fsms              []*FSM
-	fsmsMu            sync.Mutex
+type PeerInfo struct {
+	PeerAddr net.IP
+	PeerASN  uint32
+	LocalASN uint32
+}
+
+type peer struct {
+	server   *bgpServer
+	addr     net.IP
+	peerASN  uint32
+	localASN uint32
+
+	// guarded by fsmsMu
+	fsms   []*FSM
+	fsmsMu sync.Mutex
+
 	rib               routingtable.RouteTableClient
 	routerID          uint32
 	addPathSend       routingtable.ClientOptions
@@ -30,7 +39,15 @@ type Peer struct {
 	exportFilter      *filter.Filter
 }
 
-func (p *Peer) collisionHandling(callingFSM *FSM) bool {
+func (p *peer) snapshot() PeerInfo {
+	return PeerInfo{
+		PeerAddr: p.addr,
+		PeerASN:  p.peerASN,
+		LocalASN: p.localASN,
+	}
+}
+
+func (p *peer) collisionHandling(callingFSM *FSM) bool {
 	p.fsmsMu.Lock()
 	defer p.fsmsMu.Unlock()
 
@@ -82,8 +99,11 @@ func isEstablishedState(s state) bool {
 
 // 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, server *BGPServer) (*Peer, error) {
-	p := &Peer{
+func newPeer(c config.Peer, rib routingtable.RouteTableClient, server *bgpServer) (*peer, error) {
+	if c.LocalAS == 0 {
+		c.LocalAS = server.localASN
+	}
+	p := &peer{
 		server:            server,
 		addr:              c.PeerAddress,
 		peerASN:           c.PeerAS,
@@ -141,10 +161,10 @@ func filterOrDefault(f *filter.Filter) *filter.Filter {
 }
 
 // GetAddr returns the IP address of the peer
-func (p *Peer) GetAddr() net.IP {
+func (p *peer) GetAddr() net.IP {
 	return p.addr
 }
 
-func (p *Peer) Start() {
+func (p *peer) Start() {
 	p.fsms[0].start()
 }
diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go
index fef8b4e419d3b071ee9235620f85a0f0254d83f0..61c79de10315e5efa65c27e7da820b3a39aee4df 100644
--- a/protocols/bgp/server/server.go
+++ b/protocols/bgp/server/server.go
@@ -5,6 +5,7 @@ import (
 	"io"
 	"net"
 	"strings"
+	"sync"
 
 	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
@@ -17,30 +18,50 @@ const (
 	BGPVersion = 4
 )
 
-type BGPServer struct {
+type bgpServer struct {
 	listeners []*TCPListener
 	acceptCh  chan *net.TCPConn
-	peers     map[string]*Peer
+	peers     sync.Map
 	routerID  uint32
+	localASN  uint32
 }
 
-func NewBgpServer() *BGPServer {
-	return &BGPServer{
-		peers: make(map[string]*Peer),
-	}
+type BGPServer interface {
+	RouterID() uint32
+	Start(*config.Global) error
+	AddPeer(config.Peer, routingtable.RouteTableClient) error
+	GetPeerInfoAll() map[string]PeerInfo
+}
+
+func NewBgpServer() BGPServer {
+	return &bgpServer{}
+}
+
+func (b *bgpServer) GetPeerInfoAll() map[string]PeerInfo {
+	res := make(map[string]PeerInfo)
+	b.peers.Range(func(key, value interface{}) bool {
+		name := key.(string)
+		peer := value.(*peer)
+
+		res[name] = peer.snapshot()
+
+		return true
+	})
+	return res
 }
 
-func (b *BGPServer) RouterID() uint32 {
+func (b *bgpServer) RouterID() uint32 {
 	return b.routerID
 }
 
-func (b *BGPServer) Start(c *config.Global) error {
+func (b *bgpServer) Start(c *config.Global) error {
 	if err := c.SetDefaultGlobalConfigValues(); err != nil {
 		return fmt.Errorf("Failed to load defaults: %v", err)
 	}
 
 	log.Infof("ROUTER ID: %d\n", c.RouterID)
 	b.routerID = c.RouterID
+	b.localASN = c.LocalASN
 
 	if c.Listen {
 		acceptCh := make(chan *net.TCPConn, 4096)
@@ -59,51 +80,53 @@ func (b *BGPServer) Start(c *config.Global) error {
 	return nil
 }
 
-func (b *BGPServer) incomingConnectionWorker() {
+func (b *bgpServer) incomingConnectionWorker() {
 	for {
 		c := <-b.acceptCh
 
 		peerAddr := strings.Split(c.RemoteAddr().String(), ":")[0]
-		if _, ok := b.peers[peerAddr]; !ok {
+		peerInterface, ok := b.peers.Load(peerAddr)
+		if !ok {
 			c.Close()
 			log.WithFields(log.Fields{
 				"source": c.RemoteAddr(),
 			}).Warning("TCP connection from unknown source")
 			continue
 		}
+		peer := peerInterface.(*peer)
 
 		log.WithFields(log.Fields{
 			"source": c.RemoteAddr(),
 		}).Info("Incoming TCP connection")
 
 		log.WithField("Peer", peerAddr).Debug("Sending incoming TCP connection to fsm for peer")
-		fsm := NewActiveFSM2(b.peers[peerAddr])
+		fsm := NewActiveFSM2(peer)
 		fsm.state = newActiveState(fsm)
 		fsm.startConnectRetryTimer()
 
-		b.peers[peerAddr].fsmsMu.Lock()
-		b.peers[peerAddr].fsms = append(b.peers[peerAddr].fsms, fsm)
-		b.peers[peerAddr].fsmsMu.Unlock()
+		peer.fsmsMu.Lock()
+		peer.fsms = append(peer.fsms, fsm)
+		peer.fsmsMu.Unlock()
 
 		go fsm.run()
 		fsm.conCh <- c
 	}
 }
 
-func (b *BGPServer) AddPeer(c config.Peer, rib routingtable.RouteTableClient) 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")
 	}
 
-	peer, err := NewPeer(c, rib, b)
+	peer, err := newPeer(c, rib, b)
 	if err != nil {
 		return err
 	}
 
 	peer.routerID = c.RouterID
 	peerAddr := peer.GetAddr().String()
-	b.peers[peerAddr] = peer
-	b.peers[peerAddr].Start()
+	b.peers.Store(peerAddr, peer)
+	peer.Start()
 
 	return nil
 }
diff --git a/protocols/bgp/server/server_test.go b/protocols/bgp/server/server_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..86095be8e22e28168e2b66c1a70217969263fe18
--- /dev/null
+++ b/protocols/bgp/server/server_test.go
@@ -0,0 +1,85 @@
+package server
+
+import (
+	"net"
+	"testing"
+	"time"
+
+	"github.com/bio-routing/bio-rd/config"
+	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/bio-routing/bio-rd/routingtable/filter"
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+)
+
+func TestBgpServerConfigCheck(t *testing.T) {
+	s := NewBgpServer()
+
+	err := s.Start(&config.Global{})
+	if err == nil {
+		t.Fatalf("server with empty config should not start")
+	}
+
+	err = s.Start(&config.Global{
+		LocalASN: 204880,
+		RouterID: 2137,
+	})
+	if err != nil {
+		t.Fatalf("server should have started, got err: %v", err)
+	}
+}
+
+func TestBgpServerPeerSnapshot(t *testing.T) {
+	s := NewBgpServer()
+	err := s.Start(&config.Global{
+		LocalASN: 204880,
+		RouterID: 2137,
+	})
+	if err != nil {
+		t.Fatalf("server should have started, got err: %v", err)
+	}
+
+	info := s.GetPeerInfoAll()
+	if len(info) != 0 {
+		t.Fatalf("empty server should have 0 peers, has %d", len(info))
+	}
+
+	rib := locRIB.New()
+	pc := config.Peer{
+		AdminEnabled:      true,
+		PeerAS:            65300,
+		PeerAddress:       net.IP([]byte{169, 254, 200, 1}),
+		LocalAddress:      net.IP([]byte{169, 254, 200, 0}),
+		ReconnectInterval: time.Second * 15,
+		HoldTime:          time.Second * 90,
+		KeepAlive:         time.Second * 30,
+		Passive:           true,
+		RouterID:          s.RouterID(),
+		AddPathSend: routingtable.ClientOptions{
+			MaxPaths: 10,
+		},
+		ImportFilter: filter.NewDrainFilter(),
+		ExportFilter: filter.NewAcceptAllFilter(),
+	}
+	s.AddPeer(pc, rib)
+
+	info = s.GetPeerInfoAll()
+	if want, got := 1, len(info); want != got {
+		t.Fatalf("empty server should have %d peers, has %d", want, got)
+	}
+
+	var peer PeerInfo
+	for _, v := range info {
+		peer = v
+		break
+	}
+
+	if want, got := net.ParseIP("169.254.200.1"), peer.PeerAddr; !want.Equal(got) {
+		t.Errorf("PeerAddr: got %v, want %v", got, want)
+	}
+	if want, got := uint32(65300), peer.PeerASN; want != got {
+		t.Errorf("PeerASN: got %v, want %v", got, want)
+	}
+	if want, got := uint32(204880), peer.LocalASN; want != got {
+		t.Errorf("PeerASN: got %v, want %v", got, want)
+	}
+}