Skip to content
Snippets Groups Projects
Unverified Commit d873c951 authored by Daniel Czerwonk's avatar Daniel Czerwonk Committed by GitHub
Browse files

Merge pull request #54 from q3k/q3k/client

Begin implementing public interface for server/peer info 
parents f4bd67ed b9b019c7
No related branches found
No related tags found
No related merge requests found
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
# Please keep the list sorted. # Please keep the list sorted.
Cedric Kienzler Cedric Kienzler
Christoph Petrausch
Daniel Czerwonk Daniel Czerwonk
Oliver Herms Oliver Herms
Christoph Petrausch Serge Bazanski
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# but not in AUTHORS, because Google holds the copyright. # but not in AUTHORS, because Google holds the copyright.
Cedric Kienzler Cedric Kienzler
Christoph Petrausch
Daniel Czerwonk Daniel Czerwonk
Oliver Herms Oliver Herms
Christoph Petrausch Serge Bazanski
\ No newline at end of file
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
) )
type Global struct { type Global struct {
LocalAS uint32 LocalASN uint32
RouterID uint32 RouterID uint32
Port uint16 Port uint16
LocalAddressList []net.IP LocalAddressList []net.IP
......
...@@ -3,7 +3,6 @@ package main ...@@ -3,7 +3,6 @@ package main
import ( import (
"fmt" "fmt"
"net" "net"
"sync"
"time" "time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
...@@ -83,7 +82,5 @@ func main() { ...@@ -83,7 +82,5 @@ func main() {
} }
}() }()
var wg sync.WaitGroup select {}
wg.Add(1)
wg.Wait()
} }
...@@ -41,6 +41,7 @@ go_library( ...@@ -41,6 +41,7 @@ go_library(
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = [ srcs = [
"server_test.go",
"update_helper_test.go", "update_helper_test.go",
"withdraw_test.go", "withdraw_test.go",
], ],
...@@ -49,6 +50,7 @@ go_test( ...@@ -49,6 +50,7 @@ go_test(
"//net:go_default_library", "//net:go_default_library",
"//protocols/bgp/packet:go_default_library", "//protocols/bgp/packet:go_default_library",
"//route:go_default_library", "//route:go_default_library",
"//routingtable/locRIB:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
], ],
) )
...@@ -28,7 +28,7 @@ type state interface { ...@@ -28,7 +28,7 @@ type state interface {
// FSM implements the BGP finite state machine (RFC4271) // FSM implements the BGP finite state machine (RFC4271)
type FSM struct { type FSM struct {
peer *Peer peer *peer
eventCh chan int eventCh chan int
con net.Conn con net.Conn
conCh chan net.Conn conCh chan net.Conn
...@@ -72,7 +72,7 @@ type FSM struct { ...@@ -72,7 +72,7 @@ type FSM struct {
} }
// NewPassiveFSM2 initiates a new passive FSM // 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 := newFSM2(peer)
fsm.con = con fsm.con = con
fsm.state = newIdleState(fsm) fsm.state = newIdleState(fsm)
...@@ -80,14 +80,14 @@ func NewPassiveFSM2(peer *Peer, con *net.TCPConn) *FSM { ...@@ -80,14 +80,14 @@ func NewPassiveFSM2(peer *Peer, con *net.TCPConn) *FSM {
} }
// NewActiveFSM2 initiates a new passive FSM // NewActiveFSM2 initiates a new passive FSM
func NewActiveFSM2(peer *Peer) *FSM { func NewActiveFSM2(peer *peer) *FSM {
fsm := newFSM2(peer) fsm := newFSM2(peer)
fsm.active = true fsm.active = true
fsm.state = newIdleState(fsm) fsm.state = newIdleState(fsm)
return fsm return fsm
} }
func newFSM2(peer *Peer) *FSM { func newFSM2(peer *peer) *FSM {
return &FSM{ return &FSM{
connectRetryTime: time.Minute, connectRetryTime: time.Minute,
peer: peer, peer: peer,
......
...@@ -11,13 +11,22 @@ import ( ...@@ -11,13 +11,22 @@ import (
"github.com/bio-routing/bio-rd/routingtable/filter" "github.com/bio-routing/bio-rd/routingtable/filter"
) )
type Peer struct { type PeerInfo struct {
server *BGPServer PeerAddr net.IP
addr net.IP PeerASN uint32
peerASN uint32 LocalASN uint32
localASN uint32 }
fsms []*FSM
fsmsMu sync.Mutex type peer struct {
server *bgpServer
addr net.IP
peerASN uint32
localASN uint32
// guarded by fsmsMu
fsms []*FSM
fsmsMu sync.Mutex
rib routingtable.RouteTableClient rib routingtable.RouteTableClient
routerID uint32 routerID uint32
addPathSend routingtable.ClientOptions addPathSend routingtable.ClientOptions
...@@ -30,7 +39,15 @@ type Peer struct { ...@@ -30,7 +39,15 @@ type Peer struct {
exportFilter *filter.Filter 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() p.fsmsMu.Lock()
defer p.fsmsMu.Unlock() defer p.fsmsMu.Unlock()
...@@ -82,8 +99,11 @@ func isEstablishedState(s state) bool { ...@@ -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 // 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. // 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) { func newPeer(c config.Peer, rib routingtable.RouteTableClient, server *bgpServer) (*peer, error) {
p := &Peer{ if c.LocalAS == 0 {
c.LocalAS = server.localASN
}
p := &peer{
server: server, server: server,
addr: c.PeerAddress, addr: c.PeerAddress,
peerASN: c.PeerAS, peerASN: c.PeerAS,
...@@ -141,10 +161,10 @@ func filterOrDefault(f *filter.Filter) *filter.Filter { ...@@ -141,10 +161,10 @@ func filterOrDefault(f *filter.Filter) *filter.Filter {
} }
// GetAddr returns the IP address of the peer // GetAddr returns the IP address of the peer
func (p *Peer) GetAddr() net.IP { func (p *peer) GetAddr() net.IP {
return p.addr return p.addr
} }
func (p *Peer) Start() { func (p *peer) Start() {
p.fsms[0].start() p.fsms[0].start()
} }
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"io" "io"
"net" "net"
"strings" "strings"
"sync"
"github.com/bio-routing/bio-rd/config" "github.com/bio-routing/bio-rd/config"
"github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/protocols/bgp/packet"
...@@ -17,30 +18,50 @@ const ( ...@@ -17,30 +18,50 @@ const (
BGPVersion = 4 BGPVersion = 4
) )
type BGPServer struct { type bgpServer struct {
listeners []*TCPListener listeners []*TCPListener
acceptCh chan *net.TCPConn acceptCh chan *net.TCPConn
peers map[string]*Peer peers sync.Map
routerID uint32 routerID uint32
localASN uint32
} }
func NewBgpServer() *BGPServer { type BGPServer interface {
return &BGPServer{ RouterID() uint32
peers: make(map[string]*Peer), 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 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 { if err := c.SetDefaultGlobalConfigValues(); err != nil {
return fmt.Errorf("Failed to load defaults: %v", err) return fmt.Errorf("Failed to load defaults: %v", err)
} }
log.Infof("ROUTER ID: %d\n", c.RouterID) log.Infof("ROUTER ID: %d\n", c.RouterID)
b.routerID = c.RouterID b.routerID = c.RouterID
b.localASN = c.LocalASN
if c.Listen { if c.Listen {
acceptCh := make(chan *net.TCPConn, 4096) acceptCh := make(chan *net.TCPConn, 4096)
...@@ -59,51 +80,53 @@ func (b *BGPServer) Start(c *config.Global) error { ...@@ -59,51 +80,53 @@ func (b *BGPServer) Start(c *config.Global) error {
return nil return nil
} }
func (b *BGPServer) incomingConnectionWorker() { func (b *bgpServer) incomingConnectionWorker() {
for { for {
c := <-b.acceptCh c := <-b.acceptCh
peerAddr := strings.Split(c.RemoteAddr().String(), ":")[0] peerAddr := strings.Split(c.RemoteAddr().String(), ":")[0]
if _, ok := b.peers[peerAddr]; !ok { peerInterface, ok := b.peers.Load(peerAddr)
if !ok {
c.Close() c.Close()
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"source": c.RemoteAddr(), "source": c.RemoteAddr(),
}).Warning("TCP connection from unknown source") }).Warning("TCP connection from unknown source")
continue continue
} }
peer := peerInterface.(*peer)
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"source": c.RemoteAddr(), "source": c.RemoteAddr(),
}).Info("Incoming TCP connection") }).Info("Incoming TCP connection")
log.WithField("Peer", peerAddr).Debug("Sending incoming TCP connection to fsm for peer") 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.state = newActiveState(fsm)
fsm.startConnectRetryTimer() fsm.startConnectRetryTimer()
b.peers[peerAddr].fsmsMu.Lock() peer.fsmsMu.Lock()
b.peers[peerAddr].fsms = append(b.peers[peerAddr].fsms, fsm) peer.fsms = append(peer.fsms, fsm)
b.peers[peerAddr].fsmsMu.Unlock() peer.fsmsMu.Unlock()
go fsm.run() go fsm.run()
fsm.conCh <- c 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 { if c.LocalAS > uint16max || c.PeerAS > uint16max {
return fmt.Errorf("32bit ASNs are not supported yet") return fmt.Errorf("32bit ASNs are not supported yet")
} }
peer, err := NewPeer(c, rib, b) peer, err := newPeer(c, rib, b)
if err != nil { if err != nil {
return err return err
} }
peer.routerID = c.RouterID peer.routerID = c.RouterID
peerAddr := peer.GetAddr().String() peerAddr := peer.GetAddr().String()
b.peers[peerAddr] = peer b.peers.Store(peerAddr, peer)
b.peers[peerAddr].Start() peer.Start()
return nil return nil
} }
......
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)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment