diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-09-13 22:39:21 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-09-13 22:39:21 +0900 |
commit | 5be31cce0de1797664d4125957d157991a6fbd4a (patch) | |
tree | 5a54a2f12184ea6d7bface519707bf878df859f9 | |
parent | c717f53456e0c1ac256377bfdd933431cc6a66bd (diff) |
Add bmp support
Can be enabled like:
[Global]
[Global.GlobalConfig]
As = 64512
RouterId = "10.0.255.254"
[BmpServers]
[[BmpServers.BmpServerList]]
[BmpServers.BmpServerList.BmpServerConfig]
Address = "127.0.0.1"
Port=11019
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | config/bgp_configs.go | 29 | ||||
-rw-r--r-- | gobgpd/main.go | 1 | ||||
-rw-r--r-- | packet/bmp.go | 9 | ||||
-rw-r--r-- | server/bmp.go | 132 | ||||
-rw-r--r-- | server/fsm.go | 21 | ||||
-rw-r--r-- | server/peer.go | 2 | ||||
-rw-r--r-- | server/server.go | 86 | ||||
-rw-r--r-- | tools/pyang_plugins/gobgp.yang | 55 |
8 files changed, 316 insertions, 19 deletions
diff --git a/config/bgp_configs.go b/config/bgp_configs.go index a4a6c0ff..093be338 100644 --- a/config/bgp_configs.go +++ b/config/bgp_configs.go @@ -131,6 +131,33 @@ const ( BGP_ORIGIN_ATTR_TYPE_INCOMPLETE = 2 ) +//struct for container gobgp:state +type BmpServerState struct { +} + +//struct for container gobgp:config +type BmpServerConfig struct { + // original -> gobgp:address + //gobgp:address's original type is inet:ip-address + Address net.IP + // original -> gobgp:port + Port uint32 +} + +//struct for container gobgp:bmp-server +type BmpServer struct { + // original -> gobgp:bmp-server-config + BmpServerConfig BmpServerConfig + // original -> gobgp:bmp-server-state + BmpServerState BmpServerState +} + +//struct for container gobgp:bmp-servers +type BmpServers struct { + // original -> gobgp:bmp-server + BmpServerList []BmpServer +} + //struct for container gobgp:rpki-received type RpkiReceived struct { // original -> gobgp:serial-notify @@ -1320,6 +1347,8 @@ type Bgp struct { PeerGroups PeerGroups // original -> gobgp:rpki-servers RpkiServers RpkiServers + // original -> gobgp:bmp-servers + BmpServers BmpServers } //struct for container bgp-pol:set-ext-community-method diff --git a/gobgpd/main.go b/gobgpd/main.go index 0ad19255..0fcfddf6 100644 --- a/gobgpd/main.go +++ b/gobgpd/main.go @@ -179,6 +179,7 @@ func main() { bgpServer.SetGlobalType(newConfig.Bgp.Global) bgpConfig = &newConfig.Bgp bgpServer.SetRpkiConfig(newConfig.Bgp.RpkiServers) + bgpServer.SetBmpConfig(newConfig.Bgp.BmpServers) added = newConfig.Bgp.Neighbors.NeighborList deleted = []config.Neighbor{} updated = []config.Neighbor{} diff --git a/packet/bmp.go b/packet/bmp.go index 4da37779..80b74eb0 100644 --- a/packet/bmp.go +++ b/packet/bmp.go @@ -34,6 +34,11 @@ const ( BMP_PEER_HEADER_SIZE = 42 ) +const ( + BMP_PEER_TYPE_GLOBAL = iota + BMP_PEER_TYPE_L3VPN +) + func (h *BMPHeader) DecodeFromBytes(data []byte) error { h.Version = data[0] if data[0] != 3 { @@ -242,7 +247,9 @@ func (body *BMPPeerDownNotification) Serialize() ([]byte, error) { } } default: - buf = append(buf, body.Data...) + if body.Data != nil { + buf = append(buf, body.Data...) + } } return buf, nil } diff --git a/server/bmp.go b/server/bmp.go new file mode 100644 index 00000000..2a00b73d --- /dev/null +++ b/server/bmp.go @@ -0,0 +1,132 @@ +// 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 + addr string +} + +func (m *broadcastBMPMsg) send() { + m.ch <- m +} + +type bmpConn struct { + conn *net.TCPConn + addr 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 + + tryConnect := func(addr string) { + for { + conn, err := net.Dial("tcp", addr) + if err != nil { + time.Sleep(30 * time.Second) + } else { + log.Info("bmp server is connected, ", addr) + connCh <- &bmpConn{ + conn: conn.(*net.TCPConn), + addr: addr, + } + break + } + } + } + + for _, c := range conf.BmpServerList { + b := c.BmpServerConfig + go tryConnect(net.JoinHostPort(b.Address.String(), 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.addr] = m.conn + } + } + + for addr, conn := range connMap { + if m.conn != nil && m.conn != conn { + continue + } + + for _, msg := range m.msgList { + b, _ := msg.Serialize() + _, err := conn.Write(b) + if err != nil { + delete(connMap, addr) + go tryConnect(addr) + break + } + } + } + } + } + }() + + 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, u *bgp.BGPMessage) *bgp.BMPMessage { + ph := bgp.NewBMPPeerHeader(uint8(t), policy, pd, peeri.Address.String(), peeri.AS, peeri.LocalID.String(), float64(timestamp)) + return bgp.NewBMPRouteMonitoring(*ph, u) +} diff --git a/server/fsm.go b/server/fsm.go index c9950a5d..7ee1d9cc 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -170,16 +170,25 @@ func (fsm *FSM) StateChange(nextState bgp.FSMState) { } } -func (fsm *FSM) LocalAddr() net.IP { - addr := fsm.conn.LocalAddr() +func hostport(addr net.Addr) (string, uint16) { if addr != nil { - host, _, err := net.SplitHostPort(addr.String()) + host, port, err := net.SplitHostPort(addr.String()) if err != nil { - return nil + return "", 0 } - return net.ParseIP(host) + p, _ := strconv.Atoi(port) + return host, uint16(p) } - return nil + return "", 0 +} + +func (fsm *FSM) RemoteHostPort() (string, uint16) { + return hostport(fsm.conn.RemoteAddr()) + +} + +func (fsm *FSM) LocalHostPort() (string, uint16) { + return hostport(fsm.conn.LocalAddr()) } func (fsm *FSM) sendNotificatonFromErrorMsg(conn net.Conn, e *bgp.MessageError) { diff --git a/server/peer.go b/server/peer.go index 45cb1c79..24638130 100644 --- a/server/peer.go +++ b/server/peer.go @@ -44,6 +44,7 @@ type Peer struct { inPolicies []*policy.Policy defaultInPolicy config.DefaultPolicyType isConfederationMember bool + recvOpen *bgp.BGPMessage } func NewPeer(g config.Global, conf config.Neighbor) *Peer { @@ -121,6 +122,7 @@ func (peer *Peer) handleBGPmessage(m *bgp.BGPMessage) ([]*table.Path, bool, []*b switch m.Header.Type { case bgp.BGP_MSG_OPEN: + peer.recvOpen = m body := m.Body.(*bgp.BGPOpen) peer.peerInfo.ID = m.Body.(*bgp.BGPOpen).ID r := make(map[bgp.RouteFamily]bool) diff --git a/server/server.go b/server/server.go index 1699a5cb..9861ee7b 100644 --- a/server/server.go +++ b/server/server.go @@ -90,6 +90,7 @@ type BgpServer struct { deletedPeerCh chan config.Neighbor updatedPeerCh chan config.Neighbor rpkiConfigCh chan config.RpkiServers + bmpConfigCh chan config.BmpServers dumper *dumper GrpcReqCh chan *GrpcRequest @@ -103,6 +104,8 @@ type BgpServer struct { localRibMap map[string]*LocalRib zclient *zebra.Client roaClient *roaClient + bmpClient *bmpClient + bmpConnCh chan *bmpConn } func NewBgpServer(port int) *BgpServer { @@ -112,6 +115,8 @@ func NewBgpServer(port int) *BgpServer { b.deletedPeerCh = make(chan config.Neighbor) b.updatedPeerCh = make(chan config.Neighbor) b.rpkiConfigCh = make(chan config.RpkiServers) + b.bmpConfigCh = make(chan config.BmpServers) + b.bmpConnCh = make(chan *bmpConn) b.GrpcReqCh = make(chan *GrpcRequest, 1) b.policyUpdateCh = make(chan config.RoutingPolicy) b.localRibMap = make(map[string]*LocalRib) @@ -252,6 +257,32 @@ func (server *BgpServer) Serve() { select { case c := <-server.rpkiConfigCh: server.roaClient, _ = newROAClient(c) + case c := <-server.bmpConfigCh: + server.bmpClient, _ = newBMPClient(c, server.bmpConnCh) + case c := <-server.bmpConnCh: + bmpMsgList := []*bgp.BMPMessage{} + for _, targetPeer := range server.neighborMap { + pathList := make([]*table.Path, 0) + if targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED { + continue + } + for _, rf := range targetPeer.configuredRFlist() { + pathList = append(pathList, targetPeer.adjRib.GetInPathList(rf)...) + } + for _, p := range pathList { + // avoid to merge for timestamp + u := table.CreateUpdateMsgFromPaths([]*table.Path{p}) + bmpMsgList = append(bmpMsgList, bmpPeerRoute(bgp.BMP_PEER_TYPE_GLOBAL, false, 0, targetPeer.peerInfo, p.GetTimestamp().Unix(), u[0])) + } + } + + m := &broadcastBMPMsg{ + ch: server.bmpClient.send(), + conn: c.conn, + addr: c.addr, + msgList: bmpMsgList, + } + server.broadcastMsgs = append(server.broadcastMsgs, m) case rmsg := <-server.roaClient.recieveROA(): server.roaClient.handleRTRMsg(rmsg) case zmsg := <-zapiMsgCh: @@ -733,6 +764,13 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *fsmMsg, incoming chan * globalRib := server.localRibMap[GLOBAL_RIB_NAME] if oldState == bgp.BGP_FSM_ESTABLISHED { + if ch := server.bmpClient.send(); ch != nil { + m := &broadcastBMPMsg{ + ch: ch, + msgList: []*bgp.BMPMessage{bmpPeerDown(bgp.BMP_PEER_DOWN_REASON_UNKNOWN, bgp.BMP_PEER_TYPE_GLOBAL, false, 0, peer.peerInfo, peer.conf.Timers.TimersState.Downtime)}, + } + server.broadcastMsgs = append(server.broadcastMsgs, m) + } t := time.Now() if t.Sub(time.Unix(peer.conf.Timers.TimersState.Uptime, 0)) < FLOP_THRESHOLD { peer.conf.NeighborState.Flops++ @@ -748,12 +786,22 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *fsmMsg, incoming chan * close(peer.outgoing) peer.outgoing = make(chan *bgp.BGPMessage, 128) if nextState == bgp.BGP_FSM_ESTABLISHED { + if ch := server.bmpClient.send(); ch != nil { + laddr, lport := peer.fsm.LocalHostPort() + _, rport := peer.fsm.RemoteHostPort() + m := &broadcastBMPMsg{ + ch: ch, + msgList: []*bgp.BMPMessage{bmpPeerUp(laddr, lport, rport, buildopen(peer.fsm.gConf, peer.fsm.pConf), peer.recvOpen, bgp.BMP_PEER_TYPE_GLOBAL, false, 0, peer.peerInfo, peer.conf.Timers.TimersState.Uptime)}, + } + server.broadcastMsgs = append(server.broadcastMsgs, m) + } pathList := make([]*table.Path, 0) if peer.isRouteServerClient() { loc := server.localRibMap[peer.conf.NeighborConfig.NeighborAddress.String()] pathList = applyPolicies(peer, loc, POLICY_DIRECTION_EXPORT, peer.getBests(loc)) } else { - peer.conf.Transport.TransportConfig.LocalAddress = peer.fsm.LocalAddr() + l, _ := peer.fsm.LocalHostPort() + peer.conf.Transport.TransportConfig.LocalAddress = net.ParseIP(l) for _, path := range filterpath(peer, peer.getBests(globalRib)) { p := path.Clone(path.IsWithdraw) p.UpdatePathAttrs(&server.bgpConfig.Global, &peer.conf) @@ -796,18 +844,28 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *fsmMsg, incoming chan * server.roaClient.validate(pathList) } } - if m.Header.Type == bgp.BGP_MSG_UPDATE && server.dumper != nil { - _, y := peer.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER] - bm := &broadcastBGPMsg{ - message: m, - peerAS: peer.peerInfo.AS, - localAS: peer.peerInfo.LocalAS, - peerAddress: peer.peerInfo.Address, - localAddress: peer.fsm.LocalAddr(), - fourBytesAs: y, - ch: server.dumper.sendCh(), + if m.Header.Type == bgp.BGP_MSG_UPDATE { + if server.dumper != nil { + _, y := peer.capMap[bgp.BGP_CAP_FOUR_OCTET_AS_NUMBER] + l, _ := peer.fsm.LocalHostPort() + bm := &broadcastBGPMsg{ + message: m, + peerAS: peer.peerInfo.AS, + localAS: peer.peerInfo.LocalAS, + peerAddress: peer.peerInfo.Address, + localAddress: net.ParseIP(l), + fourBytesAs: y, + ch: server.dumper.sendCh(), + } + server.broadcastMsgs = append(server.broadcastMsgs, bm) + } + if ch := server.bmpClient.send(); ch != nil { + bm := &broadcastBMPMsg{ + ch: ch, + msgList: []*bgp.BMPMessage{bmpPeerRoute(bgp.BMP_PEER_TYPE_GLOBAL, false, 0, peer.peerInfo, time.Now().Unix(), m)}, + } + server.broadcastMsgs = append(server.broadcastMsgs, bm) } - server.broadcastMsgs = append(server.broadcastMsgs, bm) } msgs = append(msgs, server.propagateUpdate(peer, pathList)...) default: @@ -829,6 +887,10 @@ func (server *BgpServer) SetRpkiConfig(c config.RpkiServers) { server.rpkiConfigCh <- c } +func (server *BgpServer) SetBmpConfig(c config.BmpServers) { + server.bmpConfigCh <- c +} + func (server *BgpServer) PeerAdd(peer config.Neighbor) { server.addedPeerCh <- peer } diff --git a/tools/pyang_plugins/gobgp.yang b/tools/pyang_plugins/gobgp.yang index ad8f24b8..07daafa1 100644 --- a/tools/pyang_plugins/gobgp.yang +++ b/tools/pyang_plugins/gobgp.yang @@ -395,6 +395,56 @@ module bgp-gobgp { } } + grouping gobgp-bmp-server-config { + description "additional BMP config"; + + leaf address { + type inet:ip-address; + description + "Reference to the address of the BMP server used as + a key in the BMP server list"; + } + leaf port { + type uint32; + description + "Reference to the port of the BMP server"; + } + } + + grouping gobgp-bmp-server-state { + description "additional BMP state"; + } + + grouping gobgp-bmp-server-set { + description "additional BMP configuration and state"; + + container config { + description + "Configuration parameters relating to BMP server"; + uses gobgp-bmp-server-config; + } + + container state { + description + "Configuration parameters relating to BMP server"; + uses gobgp-bmp-server-state; + } + } + + grouping gobgp-bmp-servers { + description "BGP Monitoring Protocol servers"; + + container bmp-servers { + description + "List of BMP servers configured on the local system"; + list bmp-server { + container bmp-server { + uses gobgp-bmp-server-set; + } + } + } + } + // augment statements augment "/bgp:bgp/bgp:neighbors/bgp:neighbor/bgp:state/bgp:messages/bgp:sent" { description "additional counters"; @@ -556,6 +606,11 @@ module bgp-gobgp { uses gobgp-rpki-servers; } + augment "/bgp:bgp" { + description "additional bmp configuration"; + uses gobgp-bmp-servers; + } + augment "/bgp:bgp/bgp:global" { description "additional mrt configuration"; container mrt { |