# frozen_string_literal: true # 加载项目依赖 require_relative "netdisco/config" require_relative "netdisco/poll_map" require_relative "netdisco/name_map" require_relative "netdisco/peer" require_relative "netdisco/method/xdp" require_relative "netdisco/dns" require_relative "netdisco/output" class Netdisco class NetdiscoError < StandardError; end class MethodNotFound < NetdiscoError; end # 类对象方法属性 attr_reader :hosts # 类对象初始化函数 def initialize @methods = [] @hosts = {} @poll = PollMap.new # 动态加载邻居发现协议 CFG.use.each do |method| method = File.basename method.to_s file = "netdisco/method/#{method.downcase}" require_relative file @methods << Netdisco.const_get(method) rescue NameError, LoadError raise MethodNotFound, "unable to find method '#{method}'" end end # @param [String] host host to start discover from # @return [Netdisco::Output] def discover(host) recurse host Output.new @hosts, @poll end # @param [String] host host to get list of peers from # @return [Array] list of peers seen connected to host def neighbors(host) peers = [] # 不同协议可能发现相同的联结关系,处理完成后根据 ip 自动去重 @methods.each do |method| peers << method.send(:peers, host) end peers.flatten.uniq { |peer| peer.ip } end # Given string of IP address, recurses through peers seen and populates @hosts hash # @param [String] host host to start recurse from # @return [void] def recurse(host) # 第一步获取设备的邻居关系,同时将邻居关系缓存下来 @hosts[host] = peers = neighbors(host) # 第二步遍历邻居的邻居关系 peers.each do |peer| # 自动跳过已发现设备IP next if @hosts.has_key? peer.ip next unless @poll.include? peer.ip # 发现邻居关系 discover peer.ip end end end