Files
osrg-gobgp/server/bmp.go
T
2015-12-30 01:42:46 +09:00

180 lines
4.6 KiB
Go

// Copyright (C) 2015 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 (
log "github.com/Sirupsen/logrus"
"github.com/osrg/gobgp/config"
"github.com/osrg/gobgp/packet"
"github.com/osrg/gobgp/table"
"net"
"strconv"
"time"
)
type broadcastBMPMsg struct {
ch chan *broadcastBMPMsg
msgList []*bgp.BMPMessage
conn *net.TCPConn
}
func (m *broadcastBMPMsg) send() {
m.ch <- m
}
type bmpConn struct {
conn *net.TCPConn
host string
}
type bmpClient struct {
ch chan *broadcastBMPMsg
connCh chan *bmpConn
}
func newBMPClient(conf config.BmpServers, connCh chan *bmpConn) (*bmpClient, error) {
b := &bmpClient{}
if len(conf.BmpServerList) == 0 {
return b, nil
}
b.ch = make(chan *broadcastBMPMsg)
b.connCh = connCh
endCh := make(chan *net.TCPConn)
tryConnect := func(host string) {
interval := 1
for {
log.Debug("connecting bmp server: ", host)
conn, err := net.Dial("tcp", host)
if err != nil {
time.Sleep(time.Duration(interval) * time.Second)
if interval < 30 {
interval *= 2
}
} else {
log.Info("bmp server is connected, ", host)
go func() {
buf := make([]byte, 1)
for {
_, err := conn.Read(buf)
if err != nil {
endCh <- conn.(*net.TCPConn)
return
}
}
}()
connCh <- &bmpConn{
conn: conn.(*net.TCPConn),
host: host,
}
break
}
}
}
for _, c := range conf.BmpServerList {
b := c.Config
go tryConnect(net.JoinHostPort(b.Address, strconv.Itoa(int(b.Port))))
}
go func() {
connMap := make(map[string]*net.TCPConn)
for {
select {
case m := <-b.ch:
if m.conn != nil {
i := bgp.NewBMPInitiation([]bgp.BMPTLV{})
buf, _ := i.Serialize()
_, err := m.conn.Write(buf)
if err == nil {
connMap[m.conn.RemoteAddr().String()] = m.conn
}
}
for host, conn := range connMap {
if m.conn != nil && m.conn != conn {
continue
}
for _, msg := range m.msgList {
if msg.Header.Type == bgp.BMP_MSG_ROUTE_MONITORING {
c := func() *config.BmpServerConfig {
for _, c := range conf.BmpServerList {
b := &c.Config
if host == net.JoinHostPort(b.Address, strconv.Itoa(int(b.Port))) {
return b
}
}
return nil
}()
if c == nil {
log.Fatal(host)
}
ph := msg.PeerHeader
switch c.RouteMonitoringPolicy {
case config.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY:
if ph.IsPostPolicy != false {
continue
}
case config.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY:
if ph.IsPostPolicy != true {
continue
}
}
}
b, _ := msg.Serialize()
if _, err := conn.Write(b); err != nil {
break
}
}
}
case conn := <-endCh:
host := conn.RemoteAddr().String()
log.Debugf("bmp connection to %s killed", host)
delete(connMap, host)
go tryConnect(host)
}
}
}()
return b, nil
}
func (c *bmpClient) send() chan *broadcastBMPMsg {
return c.ch
}
func bmpPeerUp(laddr string, lport, rport uint16, sent, recv *bgp.BGPMessage, t int, policy bool, pd uint64, peeri *table.PeerInfo, timestamp int64) *bgp.BMPMessage {
ph := bgp.NewBMPPeerHeader(uint8(t), policy, pd, peeri.Address.String(), peeri.AS, peeri.LocalID.String(), float64(timestamp))
return bgp.NewBMPPeerUpNotification(*ph, laddr, lport, rport, sent, recv)
}
func bmpPeerDown(reason uint8, t int, policy bool, pd uint64, peeri *table.PeerInfo, timestamp int64) *bgp.BMPMessage {
ph := bgp.NewBMPPeerHeader(uint8(t), policy, pd, peeri.Address.String(), peeri.AS, peeri.LocalID.String(), float64(timestamp))
return bgp.NewBMPPeerDownNotification(*ph, reason, nil, []byte{})
}
func bmpPeerRoute(t int, policy bool, pd uint64, peeri *table.PeerInfo, timestamp int64, payload []byte) *bgp.BMPMessage {
ph := bgp.NewBMPPeerHeader(uint8(t), policy, pd, peeri.Address.String(), peeri.AS, peeri.LocalID.String(), float64(timestamp))
m := bgp.NewBMPRouteMonitoring(*ph, nil)
body := m.Body.(*bgp.BMPRouteMonitoring)
body.BGPUpdatePayload = payload
return m
}