2017-04-17 10:33:09 +05:30

325 lines
7.6 KiB
Go

// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/eapache/channels"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet/bgp"
"github.com/osrg/gobgp/table"
"github.com/stretchr/testify/assert"
"net"
"strconv"
"testing"
"time"
)
type MockConnection struct {
net.Conn
recvCh chan chan byte
sendBuf [][]byte
currentCh chan byte
isClosed bool
wait int
}
func NewMockConnection() *MockConnection {
m := &MockConnection{
recvCh: make(chan chan byte, 128),
sendBuf: make([][]byte, 0),
isClosed: false,
}
return m
}
func (m *MockConnection) SetWriteDeadline(t time.Time) error {
return nil
}
func (m *MockConnection) setData(data []byte) int {
dataChan := make(chan byte, 4096)
for _, b := range data {
dataChan <- b
}
m.recvCh <- dataChan
return len(dataChan)
}
func (m *MockConnection) Read(buf []byte) (int, error) {
if m.isClosed {
return 0, fmt.Errorf("already closed")
}
if m.currentCh == nil {
m.currentCh = <-m.recvCh
}
length := 0
rest := len(buf)
for i := 0; i < rest; i++ {
if len(m.currentCh) > 0 {
val := <-m.currentCh
buf[i] = val
length++
} else {
m.currentCh = nil
break
}
}
fmt.Printf("%d bytes read from peer\n", length)
return length, nil
}
func (m *MockConnection) Write(buf []byte) (int, error) {
time.Sleep(time.Duration(m.wait) * time.Millisecond)
m.sendBuf = append(m.sendBuf, buf)
msg, _ := bgp.ParseBGPMessage(buf)
fmt.Printf("%d bytes written by gobgp message type : %s\n", len(buf), showMessageType(msg.Header.Type))
return len(buf), nil
}
func showMessageType(t uint8) string {
switch t {
case bgp.BGP_MSG_KEEPALIVE:
return "BGP_MSG_KEEPALIVE"
case bgp.BGP_MSG_NOTIFICATION:
return "BGP_MSG_NOTIFICATION"
case bgp.BGP_MSG_OPEN:
return "BGP_MSG_OPEN"
case bgp.BGP_MSG_UPDATE:
return "BGP_MSG_UPDATE"
case bgp.BGP_MSG_ROUTE_REFRESH:
return "BGP_MSG_ROUTE_REFRESH"
}
return strconv.Itoa(int(t))
}
func (m *MockConnection) Close() error {
fmt.Printf("close called\n")
if !m.isClosed {
close(m.recvCh)
m.isClosed = true
}
return nil
}
func (m *MockConnection) LocalAddr() net.Addr {
return &net.TCPAddr{
IP: net.ParseIP("10.10.10.10"),
Port: bgp.BGP_PORT}
}
func TestReadAll(t *testing.T) {
assert := assert.New(t)
m := NewMockConnection()
msg := open()
expected1, _ := msg.Header.Serialize()
expected2, _ := msg.Body.Serialize()
pushBytes := func() {
fmt.Println("push 5 bytes")
m.setData(expected1[0:5])
fmt.Println("push rest")
m.setData(expected1[5:])
fmt.Println("push bytes at once")
m.setData(expected2)
}
go pushBytes()
var actual1 []byte
actual1, _ = readAll(m, bgp.BGP_HEADER_LENGTH)
fmt.Println(actual1)
assert.Equal(expected1, actual1)
var actual2 []byte
actual2, _ = readAll(m, len(expected2))
fmt.Println(actual2)
assert.Equal(expected2, actual2)
}
func TestFSMHandlerOpensent_HoldTimerExpired(t *testing.T) {
assert := assert.New(t)
m := NewMockConnection()
p, h := makePeerAndHandler()
// push mock connection
p.fsm.conn = m
p.fsm.h = h
// set keepalive ticker
p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
// set holdtime
p.fsm.opensentHoldTime = 2
state, _ := h.opensent()
assert.Equal(bgp.BGP_FSM_IDLE, state)
lastMsg := m.sendBuf[len(m.sendBuf)-1]
sent, _ := bgp.ParseBGPMessage(lastMsg)
assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
}
func TestFSMHandlerOpenconfirm_HoldTimerExpired(t *testing.T) {
assert := assert.New(t)
m := NewMockConnection()
p, h := makePeerAndHandler()
// push mock connection
p.fsm.conn = m
p.fsm.h = h
// set up keepalive ticker
p.fsm.pConf.Timers.Config.KeepaliveInterval = 1
// set holdtime
p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
state, _ := h.openconfirm()
assert.Equal(bgp.BGP_FSM_IDLE, state)
lastMsg := m.sendBuf[len(m.sendBuf)-1]
sent, _ := bgp.ParseBGPMessage(lastMsg)
assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
}
func TestFSMHandlerEstablish_HoldTimerExpired(t *testing.T) {
assert := assert.New(t)
m := NewMockConnection()
p, h := makePeerAndHandler()
// push mock connection
p.fsm.conn = m
p.fsm.h = h
// set keepalive ticker
p.fsm.pConf.Timers.State.NegotiatedHoldTime = 3
msg := keepalive()
header, _ := msg.Header.Serialize()
body, _ := msg.Body.Serialize()
pushPackets := func() {
// first keepalive from peer
m.setData(header)
m.setData(body)
}
// set holdtime
p.fsm.pConf.Timers.Config.HoldTime = 2
p.fsm.pConf.Timers.State.NegotiatedHoldTime = 2
go pushPackets()
state, _ := h.established()
time.Sleep(time.Second * 1)
assert.Equal(bgp.BGP_FSM_IDLE, state)
lastMsg := m.sendBuf[len(m.sendBuf)-1]
sent, _ := bgp.ParseBGPMessage(lastMsg)
assert.Equal(uint8(bgp.BGP_MSG_NOTIFICATION), sent.Header.Type)
assert.Equal(uint8(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED), sent.Body.(*bgp.BGPNotification).ErrorCode)
}
func TestFSMHandlerOpenconfirm_HoldtimeZero(t *testing.T) {
log.SetLevel(log.DebugLevel)
assert := assert.New(t)
m := NewMockConnection()
p, h := makePeerAndHandler()
// push mock connection
p.fsm.conn = m
p.fsm.h = h
// set up keepalive ticker
p.fsm.pConf.Timers.Config.KeepaliveInterval = 1
// set holdtime
p.fsm.pConf.Timers.State.NegotiatedHoldTime = 0
go h.openconfirm()
time.Sleep(100 * time.Millisecond)
assert.Equal(0, len(m.sendBuf))
}
func TestFSMHandlerEstablished_HoldtimeZero(t *testing.T) {
log.SetLevel(log.DebugLevel)
assert := assert.New(t)
m := NewMockConnection()
p, h := makePeerAndHandler()
// push mock connection
p.fsm.conn = m
p.fsm.h = h
// set holdtime
p.fsm.pConf.Timers.State.NegotiatedHoldTime = 0
go h.established()
time.Sleep(100 * time.Millisecond)
assert.Equal(0, len(m.sendBuf))
}
func makePeerAndHandler() (*Peer, *FSMHandler) {
p := &Peer{
fsm: NewFSM(&config.Global{}, &config.Neighbor{}, table.NewRoutingPolicy()),
outgoing: channels.NewInfiniteChannel(),
}
h := &FSMHandler{
fsm: p.fsm,
errorCh: make(chan FsmStateReason, 2),
incoming: channels.NewInfiniteChannel(),
outgoing: p.outgoing,
}
return p, h
}
func open() *bgp.BGPMessage {
p1 := bgp.NewOptionParameterCapability(
[]bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
p2 := bgp.NewOptionParameterCapability(
[]bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(bgp.RF_IPv4_UC)})
g := &bgp.CapGracefulRestartTuple{AFI: 4, SAFI: 2, Flags: 3}
p3 := bgp.NewOptionParameterCapability(
[]bgp.ParameterCapabilityInterface{bgp.NewCapGracefulRestart(true, true, 100,
[]*bgp.CapGracefulRestartTuple{g})})
p4 := bgp.NewOptionParameterCapability(
[]bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(100000)})
return bgp.NewBGPOpenMessage(11033, 303, "100.4.10.3",
[]bgp.OptionParameterInterface{p1, p2, p3, p4})
}
func keepalive() *bgp.BGPMessage {
return bgp.NewBGPKeepAliveMessage()
}