Exemplo n.º 1
0
func (w *mrtWatcher) loop() error {
	c := func() *time.Ticker {
		if w.interval == 0 {
			return &time.Ticker{}
		}
		return time.NewTicker(time.Second * time.Duration(w.interval))
	}()

	defer func() {
		if w.file != nil {
			w.file.Close()
		}
		if w.interval != 0 {
			c.Stop()
		}
	}()

	for {
		serialize := func(ev watcherEvent) ([]byte, error) {
			m := ev.(*watcherEventUpdateMsg)
			subtype := mrt.MESSAGE_AS4
			mp := mrt.NewBGP4MPMessage(m.peerAS, m.localAS, 0, m.peerAddress.String(), m.localAddress.String(), m.fourBytesAs, nil)
			mp.BGPMessagePayload = m.payload
			if m.fourBytesAs == false {
				subtype = mrt.MESSAGE
			}
			bm, err := mrt.NewMRTMessage(uint32(m.timestamp.Unix()), mrt.BGP4MP, subtype, mp)
			if err != nil {
				log.WithFields(log.Fields{
					"Topic": "mrt",
					"Data":  m,
				}).Warn(err)
				return nil, err
			}
			return bm.Serialize()
		}

		drain := func(ev watcherEvent) {
			events := make([]watcherEvent, 0, 1+len(w.ch))
			if ev != nil {
				events = append(events, ev)
			}

			for len(w.ch) > 0 {
				e := <-w.ch
				events = append(events, e)
			}

			w := func(buf []byte) {
				if _, err := w.file.Write(buf); err == nil {
					w.file.Sync()
				} else {
					log.WithFields(log.Fields{
						"Topic": "mrt",
						"Error": err,
					}).Warn(err)
				}
			}

			var b bytes.Buffer
			for _, e := range events {
				buf, err := serialize(e)
				if err != nil {
					log.WithFields(log.Fields{
						"Topic": "mrt",
						"Data":  e,
					}).Warn(err)
					continue
				}
				b.Write(buf)
				if b.Len() > 1*1000*1000 {
					w(b.Bytes())
					b.Reset()
				}
			}
			if b.Len() > 0 {
				w(b.Bytes())
			}
		}
		select {
		case <-w.t.Dying():
			drain(nil)
			return nil
		case e := <-w.ch:
			drain(e)
		case <-c.C:
			w.file.Close()
			file, err := mrtFileOpen(w.filename, w.interval)
			if err == nil {
				w.file = file
			} else {
				log.Info("can't rotate mrt file", err)
			}
		}
	}
}
Exemplo n.º 2
0
func (m *mrtWriter) loop() error {
	ops := []WatchOption{}
	switch m.dumpType {
	case config.MRT_TYPE_UPDATES:
		ops = append(ops, WatchUpdate(false))
	case config.MRT_TYPE_TABLE:
		if len(m.tablename) > 0 {
			ops = append(ops, WatchTableName(m.tablename))
		}
	}
	w := m.s.Watch(ops...)
	rotator := func() *time.Ticker {
		if m.rotationInterval == 0 {
			return &time.Ticker{}
		}
		return time.NewTicker(time.Second * time.Duration(m.rotationInterval))
	}()
	dump := func() *time.Ticker {
		if m.dumpInterval == 0 {
			return &time.Ticker{}
		}
		return time.NewTicker(time.Second * time.Duration(m.dumpInterval))
	}()

	defer func() {
		if m.file != nil {
			m.file.Close()
		}
		if m.rotationInterval != 0 {
			rotator.Stop()
		}
		if m.dumpInterval == 0 {
			dump.Stop()
		}
		w.Stop()
	}()

	for {
		serialize := func(ev WatchEvent) []*mrt.MRTMessage {
			msg := make([]*mrt.MRTMessage, 0, 1)
			switch m := ev.(type) {
			case *WatchEventUpdate:
				subtype := mrt.MESSAGE_AS4
				mp := mrt.NewBGP4MPMessage(m.PeerAS, m.LocalAS, 0, m.PeerAddress.String(), m.LocalAddress.String(), m.FourBytesAs, nil)
				mp.BGPMessagePayload = m.Payload
				if m.FourBytesAs == false {
					subtype = mrt.MESSAGE
				}
				if bm, err := mrt.NewMRTMessage(uint32(m.Timestamp.Unix()), mrt.BGP4MP, subtype, mp); err != nil {
					log.WithFields(log.Fields{
						"Topic": "mrt",
						"Data":  m,
						"Error": err,
					}).Warn("Failed to create MRT message in serialize()")
				} else {
					msg = append(msg, bm)
				}
			case *WatchEventTable:
				t := uint32(time.Now().Unix())
				peers := make([]*mrt.Peer, 0, len(m.Neighbor))
				for _, pconf := range m.Neighbor {
					peers = append(peers, mrt.NewPeer(pconf.State.Description, pconf.Config.NeighborAddress, pconf.Config.PeerAs, true))
				}
				if bm, err := mrt.NewMRTMessage(t, mrt.TABLE_DUMPv2, mrt.PEER_INDEX_TABLE, mrt.NewPeerIndexTable(m.RouterId, "", peers)); err != nil {
					break
				} else {
					msg = append(msg, bm)
				}

				idx := func(p *table.Path) uint16 {
					for i, pconf := range m.Neighbor {
						if p.GetSource().Address.String() == pconf.Config.NeighborAddress {
							return uint16(i)
						}
					}
					return uint16(len(m.Neighbor))
				}

				subtype := func(p *table.Path) mrt.MRTSubTypeTableDumpv2 {
					switch p.GetRouteFamily() {
					case bgp.RF_IPv4_UC:
						return mrt.RIB_IPV4_UNICAST
					case bgp.RF_IPv4_MC:
						return mrt.RIB_IPV4_MULTICAST
					case bgp.RF_IPv6_UC:
						return mrt.RIB_IPV6_UNICAST
					case bgp.RF_IPv6_MC:
						return mrt.RIB_IPV6_MULTICAST
					}
					return mrt.RIB_GENERIC
				}

				seq := uint32(0)
				for _, pathList := range m.PathList {
					entries := make([]*mrt.RibEntry, 0, len(pathList))
					for _, path := range pathList {
						if path.IsLocal() {
							continue
						}
						entries = append(entries, mrt.NewRibEntry(idx(path), uint32(path.GetTimestamp().Unix()), path.GetPathAttrs()))
					}
					if len(entries) > 0 {
						bm, _ := mrt.NewMRTMessage(t, mrt.TABLE_DUMPv2, subtype(pathList[0]), mrt.NewRib(seq, pathList[0].GetNlri(), entries))
						msg = append(msg, bm)
						seq++
					}
				}
			}
			return msg
		}

		drain := func(ev WatchEvent) {
			events := make([]WatchEvent, 0, 1+len(w.Event()))
			if ev != nil {
				events = append(events, ev)
			}

			for len(w.Event()) > 0 {
				events = append(events, <-w.Event())
			}

			w := func(buf []byte) {
				if _, err := m.file.Write(buf); err == nil {
					m.file.Sync()
				} else {
					log.WithFields(log.Fields{
						"Topic": "mrt",
						"Error": err,
					}).Warn("Can't write to destination MRT file")
				}
			}

			var b bytes.Buffer
			for _, e := range events {
				for _, m := range serialize(e) {
					if buf, err := m.Serialize(); err != nil {
						log.WithFields(log.Fields{
							"Topic": "mrt",
							"Data":  e,
							"Error": err,
						}).Warn("Failed to serialize event")
					} else {
						b.Write(buf)
						if b.Len() > 1*1000*1000 {
							w(b.Bytes())
							b.Reset()
						}
					}
				}
			}
			if b.Len() > 0 {
				w(b.Bytes())
			}
		}
		select {
		case <-m.dead:
			drain(nil)
			return nil
		case e := <-w.Event():
			drain(e)
		case <-rotator.C:
			m.file.Close()
			file, err := mrtFileOpen(m.filename, m.rotationInterval)
			if err == nil {
				m.file = file
			} else {
				log.WithFields(log.Fields{
					"Topic": "mrt",
					"Error": err,
				}).Warn("can't rotate MRT file")
			}
		case <-dump.C:
			w.Generate(WATCH_EVENT_TYPE_TABLE)
		}
	}
}