Example #1
0
func (w *bmpWatcher) loop() error {
	for {
		select {
		case <-w.t.Dying():
			for _, server := range w.connMap {
				if server.conn != nil {
					server.conn.Close()
				}
			}
			return nil
		case m := <-w.ctlCh:
			c := m.config
			if m.del {
				host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port)))
				if _, y := w.connMap[host]; !y {
					m.errCh <- fmt.Errorf("bmp server %s doesn't exists", host)
					continue
				}
				conn := w.connMap[host].conn
				delete(w.connMap, host)
				conn.Close()
			} else {
				host := net.JoinHostPort(c.Address, strconv.Itoa(int(c.Port)))
				if _, y := w.connMap[host]; y {
					m.errCh <- fmt.Errorf("bmp server %s already exists", host)
					continue
				}
				server := &bmpServer{
					host: host,
					typ:  c.RouteMonitoringPolicy,
				}
				w.connMap[host] = server
				go w.tryConnect(server)
			}
			m.errCh <- nil
			close(m.errCh)
		case newConn := <-w.newConnCh:
			server, y := w.connMap[newConn.RemoteAddr().String()]
			if !y {
				log.Warnf("Can't find bmp server %s", newConn.RemoteAddr().String())
				break
			}
			i := bmp.NewBMPInitiation([]bmp.BMPTLV{})
			buf, _ := i.Serialize()
			if _, err := newConn.Write(buf); err != nil {
				log.Warnf("failed to write to bmp server %s", server.host)
				go w.tryConnect(server)
				break
			}
			req := &GrpcRequest{
				RequestType: REQ_BMP_NEIGHBORS,
				ResponseCh:  make(chan *GrpcResponse, 1),
			}
			w.apiCh <- req
			write := func(req *GrpcRequest) error {
				for res := range req.ResponseCh {
					for _, msg := range res.Data.([]*bmp.BMPMessage) {
						buf, _ = msg.Serialize()
						if _, err := newConn.Write(buf); err != nil {
							log.Warnf("failed to write to bmp server %s %s", server.host, err)
							go w.tryConnect(server)
							return err
						}
					}
				}
				return nil
			}
			if err := write(req); err != nil {
				break
			}
			if server.typ != config.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY {
				req = &GrpcRequest{
					RequestType: REQ_BMP_ADJ_IN,
					ResponseCh:  make(chan *GrpcResponse, 1),
				}
				w.apiCh <- req
				if err := write(req); err != nil {
					break
				}
			}
			if server.typ != config.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY {
				req = &GrpcRequest{
					RequestType: REQ_BMP_GLOBAL,
					ResponseCh:  make(chan *GrpcResponse, 1),
				}
				w.apiCh <- req
				if err := write(req); err != nil {
					break
				}
			}
			server.conn = newConn
		case ev := <-w.ch:
			switch msg := ev.(type) {
			case *watcherEventUpdateMsg:
				info := &table.PeerInfo{
					Address: msg.peerAddress,
					AS:      msg.peerAS,
					ID:      msg.peerID,
				}
				buf, _ := bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.postPolicy, 0, info, msg.timestamp.Unix(), msg.payload).Serialize()
				for _, server := range w.connMap {
					if server.conn != nil {
						send := server.typ != config.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY && !msg.postPolicy
						send = send || (server.typ != config.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY && msg.postPolicy)
						if send {
							_, err := server.conn.Write(buf)
							if err != nil {
								log.Warnf("failed to write to bmp server %s", server.host)
							}
						}
					}
				}
			case *watcherEventStateChangedMsg:
				var bmpmsg *bmp.BMPMessage
				info := &table.PeerInfo{
					Address: msg.peerAddress,
					AS:      msg.peerAS,
					ID:      msg.peerID,
				}
				if msg.state == bgp.BGP_FSM_ESTABLISHED {
					bmpmsg = bmpPeerUp(msg.localAddress.String(), msg.localPort, msg.peerPort, msg.sentOpen, msg.recvOpen, bmp.BMP_PEER_TYPE_GLOBAL, false, 0, info, msg.timestamp.Unix())
				} else {
					bmpmsg = bmpPeerDown(bmp.BMP_PEER_DOWN_REASON_UNKNOWN, bmp.BMP_PEER_TYPE_GLOBAL, false, 0, info, msg.timestamp.Unix())
				}
				buf, _ := bmpmsg.Serialize()
				for _, server := range w.connMap {
					if server.conn != nil {
						_, err := server.conn.Write(buf)
						if err != nil {
							log.Warnf("failed to write to bmp server %s", server.host)
						}
					}
				}
			default:
				log.Warnf("unknown watcher event")
			}
		case conn := <-w.endCh:
			host := conn.RemoteAddr().String()
			log.Debugf("bmp connection to %s killed", host)
			if _, y := w.connMap[host]; y {
				w.connMap[host].conn = nil
				go w.tryConnect(w.connMap[host])
			}
		}
	}
}
Example #2
0
File: bmp.go Project: osrg/gobgp
func (b *bmpClient) loop() {
	for {
		conn := b.tryConnect()
		if conn == nil {
			break
		}

		if func() bool {
			ops := []WatchOption{WatchPeerState(true)}
			if b.typ != config.BMP_ROUTE_MONITORING_POLICY_TYPE_POST_POLICY {
				ops = append(ops, WatchUpdate(true))
			} else if b.typ != config.BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY {
				ops = append(ops, WatchPostUpdate(true))
			}
			w := b.s.Watch(ops...)
			defer w.Stop()

			write := func(msg *bmp.BMPMessage) error {
				buf, _ := msg.Serialize()
				_, err := conn.Write(buf)
				if err != nil {
					log.Warnf("failed to write to bmp server %s", b.host)
				}
				return err
			}

			if err := write(bmp.NewBMPInitiation([]bmp.BMPTLV{})); err != nil {
				return false
			}

			for {
				select {
				case ev := <-w.Event():
					switch msg := ev.(type) {
					case *WatchEventUpdate:
						info := &table.PeerInfo{
							Address: msg.PeerAddress,
							AS:      msg.PeerAS,
							ID:      msg.PeerID,
						}
						if err := write(bmpPeerRoute(bmp.BMP_PEER_TYPE_GLOBAL, msg.PostPolicy, 0, info, msg.Timestamp.Unix(), msg.Payload)); err != nil {
							return false
						}
					case *WatchEventPeerState:
						info := &table.PeerInfo{
							Address: msg.PeerAddress,
							AS:      msg.PeerAS,
							ID:      msg.PeerID,
						}
						if msg.State == bgp.BGP_FSM_ESTABLISHED {
							if err := write(bmpPeerUp(msg.LocalAddress.String(), msg.LocalPort, msg.PeerPort, msg.SentOpen, msg.RecvOpen, bmp.BMP_PEER_TYPE_GLOBAL, false, 0, info, msg.Timestamp.Unix())); err != nil {
								return false
							}
						} else {
							if err := write(bmpPeerDown(bmp.BMP_PEER_DOWN_REASON_UNKNOWN, bmp.BMP_PEER_TYPE_GLOBAL, false, 0, info, msg.Timestamp.Unix())); err != nil {
								return false
							}
						}
					}
				case <-b.dead:
					conn.Close()
					return true
				}
			}
		}() {
			return
		}
	}
}