github.com/osrg/gobgp@v2.0.0+incompatible/pkg/server/bmp.go (about) 1 // Copyright (C) 2015-2016 Nippon Telegraph and Telephone Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package server 17 18 import ( 19 "context" 20 "fmt" 21 "net" 22 "strconv" 23 "time" 24 25 api "github.com/osrg/gobgp/api" 26 "github.com/osrg/gobgp/internal/pkg/config" 27 "github.com/osrg/gobgp/internal/pkg/table" 28 "github.com/osrg/gobgp/pkg/packet/bgp" 29 "github.com/osrg/gobgp/pkg/packet/bmp" 30 log "github.com/sirupsen/logrus" 31 ) 32 33 type ribout map[string][]*table.Path 34 35 func newribout() ribout { 36 return make(map[string][]*table.Path) 37 } 38 39 // return true if we need to send the path to the BMP server 40 func (r ribout) update(p *table.Path) bool { 41 key := p.GetNlri().String() // TODO expose (*Path).getPrefix() 42 l := r[key] 43 if p.IsWithdraw { 44 if len(l) == 0 { 45 return false 46 } 47 n := make([]*table.Path, 0, len(l)) 48 for _, q := range l { 49 if p.GetSource() == q.GetSource() { 50 continue 51 } 52 n = append(n, q) 53 } 54 if len(n) == 0 { 55 delete(r, key) 56 } else { 57 r[key] = n 58 } 59 return true 60 } 61 62 if len(l) == 0 { 63 r[key] = []*table.Path{p} 64 return true 65 } 66 67 doAppend := true 68 for idx, q := range l { 69 if p.GetSource() == q.GetSource() { 70 // if we have sent the same path, don't send it again 71 if p.Equal(q) { 72 return false 73 } 74 l[idx] = p 75 doAppend = false 76 } 77 } 78 if doAppend { 79 r[key] = append(r[key], p) 80 } 81 return true 82 } 83 84 func (b *bmpClient) tryConnect() *net.TCPConn { 85 interval := 1 86 for { 87 log.WithFields(log.Fields{"Topic": "bmp"}).Debugf("Connecting BMP server:%s", b.host) 88 conn, err := net.Dial("tcp", b.host) 89 if err != nil { 90 select { 91 case <-b.dead: 92 return nil 93 default: 94 } 95 time.Sleep(time.Duration(interval) * time.Second) 96 if interval < 30 { 97 interval *= 2 98 } 99 } else { 100 log.WithFields(log.Fields{"Topic": "bmp"}).Infof("BMP server is connected:%s", b.host) 101 return conn.(*net.TCPConn) 102 } 103 } 104 } 105 106 func (b *bmpClient) Stop() { 107 close(b.dead) 108 } 109 110 func (b *bmpClient) loop() { 111 for { 112 conn := b.tryConnect() 113 if conn == nil { 114 break 115 } 116 117 if func() bool { 118 ops := []watchOption{watchPeerState(true)} 119 if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_BOTH { 120 log.WithFields( 121 log.Fields{"Topic": "bmp"}, 122 ).Warn("both option for route-monitoring-policy is obsoleted") 123 } 124 if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY || b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL { 125 ops = append(ops, watchUpdate(true)) 126 } 127 if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY || b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL { 128 ops = append(ops, watchPostUpdate(true)) 129 } 130 if b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_LOCAL_RIB || b.c.RouteMonitoringPolicy == config.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL { 131 ops = append(ops, watchBestPath(true)) 132 } 133 if b.c.RouteMirroringEnabled { 134 ops = append(ops, watchMessage(false)) 135 } 136 w := b.s.watch(ops...) 137 defer w.Stop() 138 139 var tickerCh <-chan time.Time 140 if b.c.StatisticsTimeout == 0 { 141 log.WithFields(log.Fields{"Topic": "bmp"}).Debug("statistics reports disabled") 142 } else { 143 t := time.NewTicker(time.Duration(b.c.StatisticsTimeout) * time.Second) 144 defer t.Stop() 145 tickerCh = t.C 146 } 147 148 write := func(msg *bmp.BMPMessage) error { 149 buf, _ := msg.Serialize() 150 _, err := conn.Write(buf) 151 if err != nil { 152 log.Warnf("failed to write to bmp server %s", b.host) 153 } 154 return err 155 } 156 157 if err := write(bmp.NewBMPInitiation([]bmp.BMPInfoTLVInterface{})); err != nil { 158 return false 159 } 160 161 for { 162 select { 163 case ev := <-w.Event(): 164 switch msg := ev.(type) { 165 case *watchEventUpdate: 166 info := &table.PeerInfo{ 167 Address: msg.PeerAddress, 168 AS: msg.PeerAS, 169 ID: msg.PeerID, 170 } 171 if msg.Payload == nil { 172 var pathList []*table.Path 173 if msg.Init { 174 pathList = msg.PathList 175 } else { 176 for _, p := range msg.PathList { 177 if b.ribout.update(p) { 178 pathList = append(pathList, p) 179 } 180 } 181 } 182 for _, path := range pathList { 183 for _, u := range table.CreateUpdateMsgFromPaths([]*table.Path{path}) { 184 payload, _ := u.Serialize() 185 if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, true, info, path.GetTimestamp().Unix(), payload)); err != nil { 186 return false 187 } 188 } 189 } 190 } else { 191 if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, msg.FourBytesAs, info, msg.Timestamp.Unix(), msg.Payload)); err != nil { 192 return false 193 } 194 } 195 case *watchEventBestPath: 196 info := &table.PeerInfo{ 197 Address: net.ParseIP("0.0.0.0").To4(), 198 AS: b.s.bgpConfig.Global.Config.As, 199 ID: net.ParseIP(b.s.bgpConfig.Global.Config.RouterId).To4(), 200 } 201 for _, p := range msg.PathList { 202 u := table.CreateUpdateMsgFromPaths([]*table.Path{p})[0] 203 if payload, err := u.Serialize(); err != nil { 204 return false 205 } else if err = write(bmpPeerRoute(bmp.BMP_PEER_TYPE_LOCAL_RIB, false, 0, true, info, p.GetTimestamp().Unix(), payload)); err != nil { 206 return false 207 } 208 } 209 case *watchEventPeerState: 210 if msg.State == bgp.BGP_FSM_ESTABLISHED { 211 if err := write(bmpPeerUp(msg, bmp.BMP_PEER_TYPE_GLOBAL, false, 0)); err != nil { 212 return false 213 } 214 } else { 215 if err := write(bmpPeerDown(msg, bmp.BMP_PEER_TYPE_GLOBAL, false, 0)); err != nil { 216 return false 217 } 218 } 219 case *watchEventMessage: 220 info := &table.PeerInfo{ 221 Address: msg.PeerAddress, 222 AS: msg.PeerAS, 223 ID: msg.PeerID, 224 } 225 if err := write(bmpPeerRouteMirroring(bmp.BMP_PEER_TYPE_GLOBAL, 0, info, msg.Timestamp.Unix(), msg.Message)); err != nil { 226 return false 227 } 228 } 229 case <-tickerCh: 230 var err error 231 b.s.ListPeer(context.Background(), &api.ListPeerRequest{EnableAdvertised: true}, 232 func(peer *api.Peer) { 233 if err == nil && peer.State.SessionState == api.PeerState_ESTABLISHED { 234 err = write(bmpPeerStats(bmp.BMP_PEER_TYPE_GLOBAL, 0, time.Now().Unix(), peer)) 235 } 236 }) 237 if err != nil { 238 return false 239 } 240 case <-b.dead: 241 term := bmp.NewBMPTermination([]bmp.BMPTermTLVInterface{ 242 bmp.NewBMPTermTLV16(bmp.BMP_TERM_TLV_TYPE_REASON, bmp.BMP_TERM_REASON_PERMANENTLY_ADMIN), 243 }) 244 if err := write(term); err != nil { 245 return false 246 } 247 conn.Close() 248 return true 249 } 250 } 251 }() { 252 return 253 } 254 } 255 } 256 257 type bmpClient struct { 258 s *BgpServer 259 dead chan struct{} 260 host string 261 c *config.BmpServerConfig 262 ribout ribout 263 } 264 265 func bmpPeerUp(ev *watchEventPeerState, t uint8, policy bool, pd uint64) *bmp.BMPMessage { 266 var flags uint8 = 0 267 if policy { 268 flags |= bmp.BMP_PEER_FLAG_POST_POLICY 269 } 270 ph := bmp.NewBMPPeerHeader(t, flags, pd, ev.PeerAddress.String(), ev.PeerAS, ev.PeerID.String(), float64(ev.Timestamp.Unix())) 271 return bmp.NewBMPPeerUpNotification(*ph, ev.LocalAddress.String(), ev.LocalPort, ev.PeerPort, ev.SentOpen, ev.RecvOpen) 272 } 273 274 func bmpPeerDown(ev *watchEventPeerState, t uint8, policy bool, pd uint64) *bmp.BMPMessage { 275 var flags uint8 = 0 276 if policy { 277 flags |= bmp.BMP_PEER_FLAG_POST_POLICY 278 } 279 ph := bmp.NewBMPPeerHeader(t, flags, pd, ev.PeerAddress.String(), ev.PeerAS, ev.PeerID.String(), float64(ev.Timestamp.Unix())) 280 return bmp.NewBMPPeerDownNotification(*ph, uint8(ev.StateReason.peerDownReason), ev.StateReason.BGPNotification, ev.StateReason.Data) 281 } 282 283 func bmpPeerRoute(t uint8, policy bool, pd uint64, fourBytesAs bool, peeri *table.PeerInfo, timestamp int64, payload []byte) *bmp.BMPMessage { 284 var flags uint8 = 0 285 if policy { 286 flags |= bmp.BMP_PEER_FLAG_POST_POLICY 287 } 288 if !fourBytesAs { 289 flags |= bmp.BMP_PEER_FLAG_TWO_AS 290 } 291 ph := bmp.NewBMPPeerHeader(t, flags, pd, peeri.Address.String(), peeri.AS, peeri.ID.String(), float64(timestamp)) 292 m := bmp.NewBMPRouteMonitoring(*ph, nil) 293 body := m.Body.(*bmp.BMPRouteMonitoring) 294 body.BGPUpdatePayload = payload 295 return m 296 } 297 298 func bmpPeerStats(peerType uint8, peerDist uint64, timestamp int64, peer *api.Peer) *bmp.BMPMessage { 299 var peerFlags uint8 = 0 300 ph := bmp.NewBMPPeerHeader(peerType, peerFlags, peerDist, peer.State.NeighborAddress, peer.State.PeerAs, peer.State.RouterId, float64(timestamp)) 301 received := uint64(0) 302 accepted := uint64(0) 303 for _, a := range peer.AfiSafis { 304 received += a.State.Received 305 accepted += a.State.Accepted 306 } 307 return bmp.NewBMPStatisticsReport( 308 *ph, 309 []bmp.BMPStatsTLVInterface{ 310 bmp.NewBMPStatsTLV64(bmp.BMP_STAT_TYPE_ADJ_RIB_IN, received), 311 bmp.NewBMPStatsTLV64(bmp.BMP_STAT_TYPE_LOC_RIB, accepted), 312 bmp.NewBMPStatsTLV32(bmp.BMP_STAT_TYPE_WITHDRAW_UPDATE, uint32(peer.State.Messages.Received.WithdrawUpdate)), 313 bmp.NewBMPStatsTLV32(bmp.BMP_STAT_TYPE_WITHDRAW_PREFIX, uint32(peer.State.Messages.Received.WithdrawPrefix)), 314 }, 315 ) 316 } 317 318 func bmpPeerRouteMirroring(peerType uint8, peerDist uint64, peerInfo *table.PeerInfo, timestamp int64, msg *bgp.BGPMessage) *bmp.BMPMessage { 319 var peerFlags uint8 = 0 320 ph := bmp.NewBMPPeerHeader(peerType, peerFlags, peerDist, peerInfo.Address.String(), peerInfo.AS, peerInfo.ID.String(), float64(timestamp)) 321 return bmp.NewBMPRouteMirroring( 322 *ph, 323 []bmp.BMPRouteMirrTLVInterface{ 324 // RFC7854: BGP Message TLV MUST occur last in the list of TLVs 325 bmp.NewBMPRouteMirrTLVBGPMsg(bmp.BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG, msg), 326 }, 327 ) 328 } 329 330 func (b *bmpClientManager) addServer(c *config.BmpServerConfig) error { 331 host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port))) 332 if _, y := b.clientMap[host]; y { 333 return fmt.Errorf("bmp client %s is already configured", host) 334 } 335 b.clientMap[host] = &bmpClient{ 336 s: b.s, 337 dead: make(chan struct{}), 338 host: host, 339 c: c, 340 ribout: newribout(), 341 } 342 go b.clientMap[host].loop() 343 return nil 344 } 345 346 func (b *bmpClientManager) deleteServer(c *config.BmpServerConfig) error { 347 host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port))) 348 if c, y := b.clientMap[host]; !y { 349 return fmt.Errorf("bmp client %s isn't found", host) 350 } else { 351 c.Stop() 352 delete(b.clientMap, host) 353 } 354 return nil 355 } 356 357 type bmpClientManager struct { 358 s *BgpServer 359 clientMap map[string]*bmpClient 360 } 361 362 func newBmpClientManager(s *BgpServer) *bmpClientManager { 363 return &bmpClientManager{ 364 s: s, 365 clientMap: make(map[string]*bmpClient), 366 } 367 }