github.com/osrg/gobgp/v3@v3.30.0/pkg/server/bmp.go (about) 1 // Copyright (C) 2015-2021 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 "sync/atomic" 24 "time" 25 26 api "github.com/osrg/gobgp/v3/api" 27 "github.com/osrg/gobgp/v3/internal/pkg/table" 28 "github.com/osrg/gobgp/v3/pkg/config/oc" 29 "github.com/osrg/gobgp/v3/pkg/log" 30 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 31 "github.com/osrg/gobgp/v3/pkg/packet/bmp" 32 ) 33 34 type ribout map[string][]*table.Path 35 36 func newribout() ribout { 37 return make(map[string][]*table.Path) 38 } 39 40 // return true if we need to send the path to the BMP server 41 func (r ribout) update(p *table.Path) bool { 42 key := p.GetNlri().String() // TODO expose (*Path).getPrefix() 43 l := r[key] 44 if p.IsWithdraw { 45 if len(l) == 0 { 46 return false 47 } 48 n := make([]*table.Path, 0, len(l)) 49 for _, q := range l { 50 if p.GetSource() == q.GetSource() { 51 continue 52 } 53 n = append(n, q) 54 } 55 if len(n) == 0 { 56 delete(r, key) 57 } else { 58 r[key] = n 59 } 60 return true 61 } 62 63 if len(l) == 0 { 64 r[key] = []*table.Path{p} 65 return true 66 } 67 68 doAppend := true 69 for idx, q := range l { 70 if p.GetSource() == q.GetSource() { 71 // if we have sent the same path, don't send it again 72 if p.Equal(q) { 73 return false 74 } 75 l[idx] = p 76 doAppend = false 77 } 78 } 79 if doAppend { 80 r[key] = append(r[key], p) 81 } 82 return true 83 } 84 85 func (b *bmpClient) tryConnect() *net.TCPConn { 86 interval := 1 87 for { 88 b.s.logger.Debug("Connecting to BMP server", 89 log.Fields{ 90 "Topic": "bmp", 91 "Key": b.host}) 92 conn, err := net.Dial("tcp", b.host) 93 if err != nil { 94 select { 95 case <-b.dead: 96 return nil 97 default: 98 } 99 time.Sleep(time.Duration(interval) * time.Second) 100 if interval < 30 { 101 interval *= 2 102 } 103 } else { 104 b.s.logger.Debug("Connected to BMP server", 105 log.Fields{ 106 "Topic": "bmp", 107 "Key": b.host}) 108 return conn.(*net.TCPConn) 109 } 110 } 111 } 112 113 func (b *bmpClient) Stop() { 114 close(b.dead) 115 } 116 117 func (b *bmpClient) loop() { 118 for { 119 conn := b.tryConnect() 120 if conn == nil { 121 break 122 } 123 atomic.StoreInt64(&b.uptime, time.Now().Unix()) 124 125 if func() bool { 126 defer func() { 127 atomic.StoreInt64(&b.downtime, time.Now().Unix()) 128 }() 129 ops := []watchOption{watchPeer()} 130 if b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_BOTH { 131 b.s.logger.Warn("both option for route-monitoring-policy is obsoleted", log.Fields{"Topic": "bmp"}) 132 } 133 if b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY || b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL { 134 ops = append(ops, watchUpdate(true, "", "")) 135 } 136 if b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY || b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL { 137 ops = append(ops, watchPostUpdate(true, "", "")) 138 } 139 if b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_LOCAL_RIB || b.c.RouteMonitoringPolicy == oc.BMP_ROUTE_MONITORING_POLICY_TYPE_ALL { 140 ops = append(ops, watchBestPath(true)) 141 } 142 if b.c.RouteMirroringEnabled { 143 ops = append(ops, watchMessage(false)) 144 } 145 w := b.s.watch(ops...) 146 defer w.Stop() 147 148 var tickerCh <-chan time.Time 149 if b.c.StatisticsTimeout == 0 { 150 b.s.logger.Debug("statistics reports disabled", log.Fields{"Topic": "bmp"}) 151 } else { 152 t := time.NewTicker(time.Duration(b.c.StatisticsTimeout) * time.Second) 153 defer t.Stop() 154 tickerCh = t.C 155 } 156 157 write := func(msg *bmp.BMPMessage) error { 158 buf, _ := msg.Serialize() 159 _, err := conn.Write(buf) 160 if err != nil { 161 b.s.logger.Warn("failed to write to bmp server", 162 log.Fields{ 163 "Topic": "bmp", 164 "Key": b.host}) 165 } 166 return err 167 } 168 169 tlv := []bmp.BMPInfoTLVInterface{ 170 bmp.NewBMPInfoTLVString(bmp.BMP_INIT_TLV_TYPE_SYS_NAME, b.c.SysName), 171 bmp.NewBMPInfoTLVString(bmp.BMP_INIT_TLV_TYPE_SYS_DESCR, b.c.SysDescr), 172 } 173 174 if err := write(bmp.NewBMPInitiation(tlv)); err != nil { 175 return false 176 } 177 178 for { 179 select { 180 case ev := <-w.Event(): 181 switch msg := ev.(type) { 182 case *watchEventUpdate: 183 info := &table.PeerInfo{ 184 Address: msg.PeerAddress, 185 AS: msg.PeerAS, 186 ID: msg.PeerID, 187 } 188 if msg.Payload == nil { 189 var pathList []*table.Path 190 if msg.Init { 191 pathList = msg.PathList 192 } else { 193 for _, p := range msg.PathList { 194 if b.ribout.update(p) { 195 pathList = append(pathList, p) 196 } 197 } 198 } 199 for _, path := range pathList { 200 for _, u := range table.CreateUpdateMsgFromPaths([]*table.Path{path}) { 201 payload, _ := u.Serialize() 202 if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, true, info, path.GetTimestamp().Unix(), payload)); err != nil { 203 return false 204 } 205 } 206 } 207 } else if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, msg.FourBytesAs, info, msg.Timestamp.Unix(), msg.Payload)); err != nil { 208 return false 209 } 210 case *watchEventBestPath: 211 info := &table.PeerInfo{ 212 Address: net.ParseIP("0.0.0.0").To4(), 213 AS: b.s.bgpConfig.Global.Config.As, 214 ID: net.ParseIP(b.s.bgpConfig.Global.Config.RouterId).To4(), 215 } 216 for _, p := range msg.PathList { 217 u := table.CreateUpdateMsgFromPaths([]*table.Path{p})[0] 218 if payload, err := u.Serialize(); err != nil { 219 return false 220 } else if err = write(bmpPeerRoute(bmp.BMP_PEER_TYPE_LOCAL_RIB, false, 0, true, info, p.GetTimestamp().Unix(), payload)); err != nil { 221 return false 222 } 223 } 224 case *watchEventPeer: 225 if msg.Type != PEER_EVENT_END_OF_INIT { 226 if msg.State == bgp.BGP_FSM_ESTABLISHED { 227 if err := write(bmpPeerUp(msg, bmp.BMP_PEER_TYPE_GLOBAL, false, 0)); err != nil { 228 return false 229 } 230 } else if msg.Type != PEER_EVENT_INIT && msg.OldState == bgp.BGP_FSM_ESTABLISHED { 231 if err := write(bmpPeerDown(msg, bmp.BMP_PEER_TYPE_GLOBAL, false, 0)); err != nil { 232 return false 233 } 234 } 235 } 236 case *watchEventMessage: 237 info := &table.PeerInfo{ 238 Address: msg.PeerAddress, 239 AS: msg.PeerAS, 240 ID: msg.PeerID, 241 } 242 if err := write(bmpPeerRouteMirroring(bmp.BMP_PEER_TYPE_GLOBAL, 0, info, msg.Timestamp.Unix(), msg.Message)); err != nil { 243 return false 244 } 245 } 246 case <-tickerCh: 247 var err error 248 b.s.ListPeer(context.Background(), &api.ListPeerRequest{EnableAdvertised: true}, 249 func(peer *api.Peer) { 250 if err == nil && peer.State.SessionState == api.PeerState_ESTABLISHED { 251 err = write(bmpPeerStats(bmp.BMP_PEER_TYPE_GLOBAL, 0, time.Now().Unix(), peer)) 252 } 253 }) 254 if err != nil { 255 return false 256 } 257 case <-b.dead: 258 term := bmp.NewBMPTermination([]bmp.BMPTermTLVInterface{ 259 bmp.NewBMPTermTLV16(bmp.BMP_TERM_TLV_TYPE_REASON, bmp.BMP_TERM_REASON_PERMANENTLY_ADMIN), 260 }) 261 if err := write(term); err != nil { 262 return false 263 } 264 conn.Close() 265 return true 266 } 267 } 268 }() { 269 return 270 } 271 } 272 } 273 274 type bmpClient struct { 275 s *BgpServer 276 dead chan struct{} 277 host string 278 c *oc.BmpServerConfig 279 ribout ribout 280 uptime int64 281 downtime int64 282 } 283 284 func bmpPeerUp(ev *watchEventPeer, t uint8, policy bool, pd uint64) *bmp.BMPMessage { 285 var flags uint8 = 0 286 if policy { 287 flags |= bmp.BMP_PEER_FLAG_POST_POLICY 288 } 289 ph := bmp.NewBMPPeerHeader(t, flags, pd, ev.PeerAddress.String(), ev.PeerAS, ev.PeerID.String(), float64(ev.Timestamp.Unix())) 290 return bmp.NewBMPPeerUpNotification(*ph, ev.LocalAddress.String(), ev.LocalPort, ev.PeerPort, ev.SentOpen, ev.RecvOpen) 291 } 292 293 func bmpPeerDown(ev *watchEventPeer, t uint8, policy bool, pd uint64) *bmp.BMPMessage { 294 var flags uint8 = 0 295 if policy { 296 flags |= bmp.BMP_PEER_FLAG_POST_POLICY 297 } 298 ph := bmp.NewBMPPeerHeader(t, flags, pd, ev.PeerAddress.String(), ev.PeerAS, ev.PeerID.String(), float64(ev.Timestamp.Unix())) 299 300 reasonCode := bmp.BMP_peerDownByUnknownReason 301 switch ev.StateReason.Type { 302 case fsmDying, fsmInvalidMsg, fsmNotificationSent, fsmHoldTimerExpired, fsmIdleTimerExpired, fsmRestartTimerExpired: 303 reasonCode = bmp.BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION 304 case fsmAdminDown: 305 reasonCode = bmp.BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION 306 case fsmNotificationRecv, fsmGracefulRestart, fsmHardReset: 307 reasonCode = bmp.BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION 308 case fsmReadFailed, fsmWriteFailed: 309 reasonCode = bmp.BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION 310 case fsmDeConfigured: 311 reasonCode = bmp.BMP_PEER_DOWN_REASON_PEER_DE_CONFIGURED 312 } 313 return bmp.NewBMPPeerDownNotification(*ph, uint8(reasonCode), ev.StateReason.BGPNotification, ev.StateReason.Data) 314 } 315 316 func bmpPeerRoute(t uint8, policy bool, pd uint64, fourBytesAs bool, peeri *table.PeerInfo, timestamp int64, payload []byte) *bmp.BMPMessage { 317 var flags uint8 = 0 318 if policy { 319 flags |= bmp.BMP_PEER_FLAG_POST_POLICY 320 } 321 if !fourBytesAs { 322 flags |= bmp.BMP_PEER_FLAG_TWO_AS 323 } 324 ph := bmp.NewBMPPeerHeader(t, flags, pd, peeri.Address.String(), peeri.AS, peeri.ID.String(), float64(timestamp)) 325 m := bmp.NewBMPRouteMonitoring(*ph, nil) 326 body := m.Body.(*bmp.BMPRouteMonitoring) 327 body.BGPUpdatePayload = payload 328 return m 329 } 330 331 func bmpPeerStats(peerType uint8, peerDist uint64, timestamp int64, peer *api.Peer) *bmp.BMPMessage { 332 var peerFlags uint8 = 0 333 ph := bmp.NewBMPPeerHeader(peerType, peerFlags, peerDist, peer.State.NeighborAddress, peer.State.PeerAsn, peer.State.RouterId, float64(timestamp)) 334 received := uint64(0) 335 accepted := uint64(0) 336 for _, a := range peer.AfiSafis { 337 received += a.State.Received 338 accepted += a.State.Accepted 339 } 340 return bmp.NewBMPStatisticsReport( 341 *ph, 342 []bmp.BMPStatsTLVInterface{ 343 bmp.NewBMPStatsTLV64(bmp.BMP_STAT_TYPE_ADJ_RIB_IN, received), 344 bmp.NewBMPStatsTLV64(bmp.BMP_STAT_TYPE_LOC_RIB, accepted), 345 bmp.NewBMPStatsTLV32(bmp.BMP_STAT_TYPE_WITHDRAW_UPDATE, uint32(peer.State.Messages.Received.WithdrawUpdate)), 346 bmp.NewBMPStatsTLV32(bmp.BMP_STAT_TYPE_WITHDRAW_PREFIX, uint32(peer.State.Messages.Received.WithdrawPrefix)), 347 }, 348 ) 349 } 350 351 func bmpPeerRouteMirroring(peerType uint8, peerDist uint64, peerInfo *table.PeerInfo, timestamp int64, msg *bgp.BGPMessage) *bmp.BMPMessage { 352 var peerFlags uint8 = 0 353 ph := bmp.NewBMPPeerHeader(peerType, peerFlags, peerDist, peerInfo.Address.String(), peerInfo.AS, peerInfo.ID.String(), float64(timestamp)) 354 return bmp.NewBMPRouteMirroring( 355 *ph, 356 []bmp.BMPRouteMirrTLVInterface{ 357 // RFC7854: BGP Message TLV MUST occur last in the list of TLVs 358 bmp.NewBMPRouteMirrTLVBGPMsg(bmp.BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG, msg), 359 }, 360 ) 361 } 362 363 func (b *bmpClientManager) addServer(c *oc.BmpServerConfig) error { 364 host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port))) 365 if _, y := b.clientMap[host]; y { 366 return fmt.Errorf("bmp client %s is already configured", host) 367 } 368 b.clientMap[host] = &bmpClient{ 369 s: b.s, 370 dead: make(chan struct{}), 371 host: host, 372 c: c, 373 ribout: newribout(), 374 } 375 go b.clientMap[host].loop() 376 return nil 377 } 378 379 func (b *bmpClientManager) deleteServer(c *oc.BmpServerConfig) error { 380 host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port))) 381 if c, y := b.clientMap[host]; !y { 382 return fmt.Errorf("bmp client %s isn't found", host) 383 } else { 384 c.Stop() 385 delete(b.clientMap, host) 386 } 387 return nil 388 } 389 390 type bmpClientManager struct { 391 s *BgpServer 392 clientMap map[string]*bmpClient 393 } 394 395 func newBmpClientManager(s *BgpServer) *bmpClientManager { 396 return &bmpClientManager{ 397 s: s, 398 clientMap: make(map[string]*bmpClient), 399 } 400 }