예제 #1
0
파일: neighbor.py 프로젝트: fobser/exabgp
class Neighbor (object):
	def __init__ (self):
		# self.logger should not be used here as long as we do use deepcopy as it contains a Lock
		self.description = ''
		self.router_id = None
		self.local_address = None
		self.peer_address = None
		self.peer_as = None
		self.local_as = None
		self.hold_time = HoldTime(180)
		self.asn4 = None
		self.add_path = 0
		self.md5 = None
		self.ttl = None
		self.group_updates = None
		self.flush = None
		self.adjribout = None

		self.api = APIOptions()

		# passive indicate that we do not establish outgoing connections
		self.passive = False
		# the port to listen on ( zero mean that we do not listen )
		self.listen = 0

		# capability
		self.route_refresh = False
		self.graceful_restart = False
		self.multisession = None
		self.add_path = None
		self.aigp = None

		self._families = []
		self.rib = None

		# The routes we have parsed from the configuration
		self.changes = []
		# On signal update, the previous routes so we can compare what changed
		self.backup_changes = []

		self.operational = None
		self.eor = deque()
		self.asm = dict()

		self.messages = deque()
		self.refresh = deque()

		self.counter = Counter()

	def identificator (self):
		# It is possible to :
		# - have multiple exabgp toward one peer on the same host ( use of pid )
		# - have more than once connection toward a peer
		# - each connection has it own neihgbor (hence why identificator is not in Protocol)
		return str(self.peer_address)

	def make_rib (self):
		self.rib = RIB(self.name(),self.adjribout,self._families)

	# will resend all the routes once we reconnect
	def reset_rib (self):
		self.rib.reset()
		self.messages = deque()
		self.refresh = deque()

	# back to square one, all the routes are removed
	def clear_rib (self):
		self.rib.clear()
		self.messages = deque()
		self.refresh = deque()

	def name (self):
		if self.multisession:
			session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
		else:
			session = 'in-open'
		return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (self.peer_address,self.local_address,self.local_as,self.peer_as,self.router_id,session)

	def families (self):
		# this list() is important .. as we use the function to modify self._families
		return list(self._families)

	def add_family (self, family):
		# the families MUST be sorted for neighbor indexing name to be predictable for API users
		if family not in self.families():
			afi,safi = family
			d = dict()
			d[afi] = [safi,]
			for afi,safi in self._families:
				d.setdefault(afi,[]).append(safi)
			self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

	def remove_family (self, family):
		if family in self.families():
			self._families.remove(family)

	def missing (self):
		if self.local_address is None:
			return 'local-address'
		if self.peer_address is None:
			return 'peer-address'
		if self.local_as is None:
			return 'local-as'
		if self.peer_as is None:
			return 'peer-as'
		if self.peer_address.afi == AFI.ipv6 and not self.router_id:
			return 'router-id'
		return ''

	# This function only compares the neighbor BUT NOT ITS ROUTES
	def __eq__ (self, other):
		return \
			self.router_id == other.router_id and \
			self.local_address == other.local_address and \
			self.local_as == other.local_as and \
			self.peer_address == other.peer_address and \
			self.peer_as == other.peer_as and \
			self.passive == other.passive and \
			self.listen == other.listen and \
			self.hold_time == other.hold_time and \
			self.md5 == other.md5 and \
			self.ttl == other.ttl and \
			self.route_refresh == other.route_refresh and \
			self.graceful_restart == other.graceful_restart and \
			self.multisession == other.multisession and \
			self.add_path == other.add_path and \
			self.operational == other.operational and \
			self.group_updates == other.group_updates and \
			self.flush == other.flush and \
			self.adjribout == other.adjribout and \
			self.families() == other.families()

	def __ne__ (self, other):
		return not self.__eq__(other)

	def pprint (self, with_changes=True):
		changes = ''
		if with_changes:
			changes += '\nstatic { '
			for changes in self.rib.incoming.queued_changes():
				changes += '\n\t\t%s' % changes.extensive()
			changes += '\n}'

		families = ''
		for afi,safi in self.families():
			families += '\n\t\t%s %s;' % (afi.name(),safi.name())

		_extension_receive = {
			'receive-parsed':           'parsed',
			'receive-packets':          'packets',
			'receive-parsed':           'parsed',
			'consolidate':              'consolidate',
			'neighbor-changes':         'neighbor-changes',
			Message.CODE.NOTIFICATION:  'notification',
			Message.CODE.OPEN:          'open',
			Message.CODE.KEEPALIVE:     'keepalive',
			Message.CODE.UPDATE:        'update',
			Message.CODE.ROUTE_REFRESH: 'refresh',
			Message.CODE.OPERATIONAL:   'operational',
		}

		_extension_send = {
			'send-packets': 'packets',
		}

		_receive = []
		for api,name in _extension_receive.items():
			_receive.extend(['\t\t\t%s;\n' % name,] if self.api[api] else [])
		receive = ''.join(_receive)

		_send = []
		for api,name in _extension_send.items():
			_send.extend(['\t\t\t%s;\n' % name,] if self.api[api] else [])
		send = ''.join(_send)

		returned = \
			'neighbor %s {\n' \
			'\tdescription "%s";\n' \
			'\trouter-id %s;\n' \
			'\tlocal-address %s;\n' \
			'\tlocal-as %s;\n' \
			'\tpeer-as %s;%s\n' \
			'\thold-time %s;\n' \
			'%s%s%s%s%s%s\n' \
			'\tcapability {\n' \
			'%s%s%s%s%s%s%s\t}\n' \
			'\tfamily {%s\n' \
			'\t}\n' \
			'\tprocess {\n' \
			'%s%s\t}%s\n' \
			'}' % (
				self.peer_address,
				self.description,
				self.router_id,
				self.local_address,
				self.local_as,
				self.peer_as,
				self.hold_time,
				'\n\tpassive;\n' if self.passive else '',
				'\n\tlisten %d;\n' % self.listen if self.listen else '',
				'\tgroup-updates: %s;\n' % (self.group_updates if self.group_updates else ''),
				'\tauto-flush: %s;\n' % ('true' if self.flush else 'false'),
				'\tadj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'),
				'\tmd5 "%s";\n' % self.md5 if self.md5 else '',
				'\tttl-security: %s;\n' % (self.ttl if self.ttl else ''),
				'\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'),
				'\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'),
				'\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'),
				'\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'),
				'\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'),
				'\t\toperational %s;\n' % ('enable' if self.operational else 'disable'),
				'\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'),
				families,
				'\t\treceive {\n%s\t\t}\n' % receive if receive else '',
				'\t\tsend {\n%s\t\t}\n' % send if send else '',
				changes
			)
		return returned.replace('\t','  ')

	def __str__ (self):
		return self.pprint(False)
예제 #2
0
class Neighbor (object):
	def __init__ (self):
		# self.logger should not be used here as long as we do use deepcopy as it contains a Lock
		self.description = ''
		self.router_id = None
		self.local_address = None
		self.peer_address = None
		self.peer_as = None
		self.local_as = None
		self.hold_time = HoldTime(180)
		self.asn4 = None
		self.add_path = 0
		self.md5 = None
		self.ttl = None
		self.group_updates = None
		self.flush = None

		self.api = APIOptions()

		self.passive = False

		# capability
		self.route_refresh = False
		self.graceful_restart = False
		self.multisession = None
		self.add_path = None
		self.aigp = None

		self._families = []
		self.rib = None

		self.operational = None
		self.asm = dict()

		self.messages = deque()
		self.refresh = deque()

	def make_rib (self):
		self.rib = RIB(self.name(),self._families)

	# will resend all the routes once we reconnect
	def reset_rib (self):
		self.rib.reset()
		self.messages = deque()
		self.refresh = deque()

	# back to square one, all the routes are removed
	def clear_rib (self):
		self.rib.clear()
		self.messages = deque()
		self.refresh = deque()

	def name (self):
		if self.multisession:
			session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
		else:
			session = 'in-open'
		return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (self.peer_address,self.local_address,self.local_as,self.peer_as,self.router_id,session)

	def families (self):
		# this list() is important .. as we use the function to modify self._families
		return list(self._families)

	def add_family (self,family):
		# the families MUST be sorted for neighbor indexing name to be predictable for API users
		if not family in self.families():
			afi,safi = family
			d = dict()
			d[afi] = [safi,]
			for afi,safi in self._families:
				d.setdefault(afi,[]).append(safi)
			self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

	def remove_family (self,family):
		if family in self.families():
			self._families.remove(family)

	def missing (self):
		if self.local_address is None: return 'local-address'
		if self.peer_address is None: return 'peer-address'
		if self.local_as is None: return 'local-as'
		if self.peer_as is None: return 'peer-as'
		if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id'
		return ''

	# This function only compares the neighbor BUT NOT ITS ROUTES
	def __eq__ (self,other):
		return \
			self.router_id == other.router_id and \
			self.local_address == other.local_address and \
			self.local_as == other.local_as and \
			self.peer_address == other.peer_address and \
			self.peer_as == other.peer_as and \
			self.passive == other.passive and \
			self.hold_time == other.hold_time and \
			self.md5 == other.md5 and \
			self.ttl == other.ttl and \
			self.route_refresh == other.route_refresh and \
			self.graceful_restart == other.graceful_restart and \
			self.multisession == other.multisession and \
			self.add_path == other.add_path and \
			self.operational == other.operational and \
			self.group_updates == other.group_updates and \
			self.flush == other.flush and \
			self.families() == other.families()

	def __ne__(self, other):
		return not self.__eq__(other)

	def pprint (self,with_changes=True):
		changes=''
		if with_changes:
			changes += '\nstatic { '
			for changes in self.rib.incoming.queued_changes():
				changes += '\n    %s' % changes.extensive()
			changes += '\n}'

		families = ''
		for afi,safi in self.families():
			families += '\n    %s %s;' % (afi.name(),safi.name())

		_api  = []
		_api.extend(['    neighbor-changes;\n',]    if self.api.neighbor_changes else [])
		_api.extend(['    receive-packets;\n',]     if self.api.receive_packets else [])
		_api.extend(['    send-packets;\n',]        if self.api.send_packets else [])
		_api.extend(['    receive-routes;\n',]      if self.api.receive_routes else [])
		_api.extend(['    receive-operational;\n',] if self.api.receive_operational else [])
		api = ''.join(_api)

		return """\
neighbor %s {
  description "%s";
  router-id %s;
  local-address %s;
  local-as %s;
  peer-as %s;%s
  hold-time %s;
%s%s%s%s
  capability {
%s%s%s%s%s%s%s  }
  family {%s
  }
  process {
%s  }%s
}""" % (
	self.peer_address,
	self.description,
	self.router_id,
	self.local_address,
	self.local_as,
	self.peer_as,
	'\n  passive;\n' if self.passive else '',
	self.hold_time,
	'  group-updates: %s;\n' % self.group_updates if self.group_updates else '',
	'  auto-flush: %s;\n' % 'true' if self.flush else 'false',
	'  md5: %d;\n' % self.ttl if self.ttl else '',
	'  ttl-security: %d;\n' % self.ttl if self.ttl else '',
	'    asn4 enable;\n' if self.asn4 else '    asn4 disable;\n',
	'    route-refresh;\n' if self.route_refresh else '',
	'    graceful-restart %s;\n' % self.graceful_restart if self.graceful_restart else '',
	'    add-path %s;\n' % AddPath.string[self.add_path] if self.add_path else '',
	'    multi-session;\n' if self.multisession else '',
	'    operational;\n' if self.operational else '',
	'    aigp;\n' if self.aigp else '',
	families,
	api,
	changes
)

	def __str__ (self):
		return self.pprint(False)
예제 #3
0
class Neighbor(object):
    def __init__(self):
        # self.logger should not be used here as long as we do use deepcopy as it contains a Lock
        self.description = ''
        self.router_id = None
        self.local_address = None
        self.peer_address = None
        self.peer_as = None
        self.local_as = None
        self.hold_time = HoldTime(180)
        self.asn4 = None
        self.add_path = 0
        self.md5 = None
        self.ttl = None
        self.group_updates = None
        self.flush = None
        self.adjribout = None

        self.api = APIOptions()

        # passive indicate that we do not establish outgoing connections
        self.passive = False
        # the port to listen on ( zero mean that we do not listen )
        self.listen = 0

        # capability
        self.route_refresh = False
        self.graceful_restart = False
        self.multisession = None
        self.add_path = None
        self.aigp = None

        self._families = []
        self.rib = None

        # The routes we have parsed from the configuration
        self.changes = []
        # On signal update, the previous routes so we can compare what changed
        self.backup_changes = []

        self.operational = None
        self.eor = deque()
        self.asm = dict()

        self.messages = deque()
        self.refresh = deque()

        self.counter = Counter()

    def identificator(self):
        # It is possible to :
        # - have multiple exabgp toward one peer on the same host ( use of pid )
        # - have more than once connection toward a peer
        # - each connection has it own neihgbor (hence why identificator is not in Protocol)
        return str(self.peer_address)

    def make_rib(self):
        self.rib = RIB(self.name(), self.adjribout, self._families)

    # will resend all the routes once we reconnect
    def reset_rib(self):
        self.rib.reset()
        self.messages = deque()
        self.refresh = deque()

    # back to square one, all the routes are removed
    def clear_rib(self):
        self.rib.clear()
        self.messages = deque()
        self.refresh = deque()

    def name(self):
        if self.multisession:
            session = '/'.join("%s-%s" % (afi.name(), safi.name())
                               for (afi, safi) in self.families())
        else:
            session = 'in-open'
        return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (
            self.peer_address, self.local_address, self.local_as, self.peer_as,
            self.router_id, session)

    def families(self):
        # this list() is important .. as we use the function to modify self._families
        return list(self._families)

    def add_family(self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        if family not in self.families():
            afi, safi = family
            d = dict()
            d[afi] = [
                safi,
            ]
            for afi, safi in self._families:
                d.setdefault(afi, []).append(safi)
            self._families = [(afi, safi) for afi in sorted(d)
                              for safi in sorted(d[afi])]

    def remove_family(self, family):
        if family in self.families():
            self._families.remove(family)

    def missing(self):
        if self.local_address is None:
            return 'local-address'
        if self.peer_address is None:
            return 'peer-address'
        if self.local_as is None:
            return 'local-as'
        if self.peer_as is None:
            return 'peer-as'
        if self.peer_address.afi == AFI.ipv6 and not self.router_id:
            return 'router-id'
        return ''

    # This function only compares the neighbor BUT NOT ITS ROUTES
    def __eq__(self, other):
        return \
         self.router_id == other.router_id and \
         self.local_address == other.local_address and \
         self.local_as == other.local_as and \
         self.peer_address == other.peer_address and \
         self.peer_as == other.peer_as and \
         self.passive == other.passive and \
         self.listen == other.listen and \
         self.hold_time == other.hold_time and \
         self.md5 == other.md5 and \
         self.ttl == other.ttl and \
         self.route_refresh == other.route_refresh and \
         self.graceful_restart == other.graceful_restart and \
         self.multisession == other.multisession and \
         self.add_path == other.add_path and \
         self.operational == other.operational and \
         self.group_updates == other.group_updates and \
         self.flush == other.flush and \
         self.adjribout == other.adjribout and \
         self.families() == other.families()

    def __ne__(self, other):
        return not self.__eq__(other)

    def pprint(self, with_changes=True):
        changes = ''
        if with_changes:
            changes += '\nstatic { '
            for changes in self.rib.incoming.queued_changes():
                changes += '\n\t\t%s' % changes.extensive()
            changes += '\n}'

        families = ''
        for afi, safi in self.families():
            families += '\n\t\t%s %s;' % (afi.name(), safi.name())

        _extension_receive = {
            'receive-parsed': 'parsed',
            'receive-packets': 'packets',
            'receive-parsed': 'parsed',
            'consolidate': 'consolidate',
            'neighbor-changes': 'neighbor-changes',
            Message.CODE.NOTIFICATION: 'notification',
            Message.CODE.OPEN: 'open',
            Message.CODE.KEEPALIVE: 'keepalive',
            Message.CODE.UPDATE: 'update',
            Message.CODE.ROUTE_REFRESH: 'refresh',
            Message.CODE.OPERATIONAL: 'operational',
        }

        _extension_send = {
            'send-packets': 'packets',
        }

        _receive = []
        for api, name in _extension_receive.items():
            _receive.extend([
                '\t\t\t%s;\n' % name,
            ] if self.api[api] else [])
        receive = ''.join(_receive)

        _send = []
        for api, name in _extension_send.items():
            _send.extend([
                '\t\t\t%s;\n' % name,
            ] if self.api[api] else [])
        send = ''.join(_send)

        returned = \
         'neighbor %s {\n' \
         '\tdescription "%s";\n' \
         '\trouter-id %s;\n' \
         '\tlocal-address %s;\n' \
         '\tlocal-as %s;\n' \
         '\tpeer-as %s;%s\n' \
         '\thold-time %s;\n' \
         '%s%s%s%s%s%s\n' \
         '\tcapability {\n' \
         '%s%s%s%s%s%s%s\t}\n' \
         '\tfamily {%s\n' \
         '\t}\n' \
         '\tprocess {\n' \
         '%s%s\t}%s\n' \
         '}' % (
          self.peer_address,
          self.description,
          self.router_id,
          self.local_address,
          self.local_as,
          self.peer_as,
          self.hold_time,
          '\n\tpassive;\n' if self.passive else '',
          '\n\tlisten %d;\n' % self.listen if self.listen else '',
          '\tgroup-updates: %s;\n' % (self.group_updates if self.group_updates else ''),
          '\tauto-flush: %s;\n' % ('true' if self.flush else 'false'),
          '\tadj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'),
          '\tmd5 "%s";\n' % self.md5 if self.md5 else '',
          '\tttl-security: %s;\n' % (self.ttl if self.ttl else ''),
          '\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'),
          '\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'),
          '\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'),
          '\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'),
          '\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'),
          '\t\toperational %s;\n' % ('enable' if self.operational else 'disable'),
          '\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'),
          families,
          '\t\treceive {\n%s\t\t}\n' % receive if receive else '',
          '\t\tsend {\n%s\t\t}\n' % send if send else '',
          changes
         )
        return returned.replace('\t', '  ')

    def __str__(self):
        return self.pprint(False)
예제 #4
0
파일: neighbor.py 프로젝트: qz267/exabgp
class Neighbor(object):
    def __init__(self):
        # self.logger should not be used here as long as we do use deepcopy as it contains a Lock
        self.description = None
        self.router_id = None
        self.host_name = None
        self.domain_name = None
        self.local_address = None
        self.peer_address = None
        self.peer_as = None
        self.local_as = None
        self.hold_time = None
        self.asn4 = None
        self.add_path = None
        self.md5 = None
        self.ttl = None
        self.group_updates = None
        self.flush = None
        self.adjribout = None

        self.manual_eor = False

        self.api = None

        # passive indicate that we do not establish outgoing connections
        self.passive = False
        # the port to listen on ( zero mean that we do not listen )
        self.listen = 0

        # capability
        self.route_refresh = False
        self.graceful_restart = False
        self.multisession = None
        self.add_path = None
        self.aigp = None

        self._families = []
        self.rib = None

        # The routes we have parsed from the configuration
        self.changes = []
        # On signal update, the previous routes so we can compare what changed
        self.backup_changes = []

        self.operational = None
        self.eor = deque()
        self.asm = dict()

        self.messages = deque()
        self.refresh = deque()

        self.counter = Counter()
        # It is possible to :
        # - have multiple exabgp toward one peer on the same host ( use of pid )
        # - have more than once connection toward a peer
        # - each connection has it own neihgbor (hence why identificator is not in Protocol)
        self.uid = "%d-%s" % (os.getpid(), uuid.uuid1())

    def make_rib(self):
        self.rib = RIB(self.name(), self.adjribout, self._families)

        # will resend all the routes once we reconnect

    def reset_rib(self):
        self.rib.reset()
        self.messages = deque()
        self.refresh = deque()

        # back to square one, all the routes are removed

    def clear_rib(self):
        self.rib.clear()
        self.messages = deque()
        self.refresh = deque()

    def name(self):
        if self.multisession:
            session = "/".join("%s-%s" % (afi.name(), safi.name()) for (afi, safi) in self.families())
        else:
            session = "in-open"
        return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (
            self.peer_address,
            self.local_address,
            self.local_as,
            self.peer_as,
            self.router_id,
            session,
        )

    def families(self):
        # this list() is important .. as we use the function to modify self._families
        return list(self._families)

    def add_family(self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        if family not in self.families():
            afi, safi = family
            d = dict()
            d[afi] = [safi]
            for afi, safi in self._families:
                d.setdefault(afi, []).append(safi)
            self._families = [(afi, safi) for afi in sorted(d) for safi in sorted(d[afi])]

    def remove_family(self, family):
        if family in self.families():
            self._families.remove(family)

    def missing(self):
        if self.local_address is None:
            return "local-address"
        if self.peer_address is None:
            return "peer-address"
        if self.local_as is None:
            return "local-as"
        if self.peer_as is None:
            return "peer-as"
        if self.peer_address.afi == AFI.ipv6 and not self.router_id:
            return "router-id"
        return ""

        # This function only compares the neighbor BUT NOT ITS ROUTES

    def __eq__(self, other):
        return (
            self.router_id == other.router_id
            and self.local_address == other.local_address
            and self.local_as == other.local_as
            and self.peer_address == other.peer_address
            and self.peer_as == other.peer_as
            and self.passive == other.passive
            and self.listen == other.listen
            and self.hold_time == other.hold_time
            and self.host_name == other.host_name
            and self.domain_name == other.domain_name
            and self.md5 == other.md5
            and self.ttl == other.ttl
            and self.route_refresh == other.route_refresh
            and self.graceful_restart == other.graceful_restart
            and self.multisession == other.multisession
            and self.add_path == other.add_path
            and self.operational == other.operational
            and self.group_updates == other.group_updates
            and self.flush == other.flush
            and self.adjribout == other.adjribout
            and self.families() == other.families()
        )

    def __ne__(self, other):
        return not self.__eq__(other)

    def pprint(self, with_changes=True):
        changes = ""
        if with_changes:
            changes += "\nstatic { "
            for changes in self.rib.incoming.queued_changes():
                changes += "\n\t\t%s" % changes.extensive()
            changes += "\n}"

        families = ""
        for afi, safi in self.families():
            families += "\n\t\t%s %s;" % (afi.name(), safi.name())

        codes = Message.CODE

        _extension_receive = {
            "receive-packets": "packets",
            "receive-parsed": "parsed",
            "receive-consolidate": "consolidate",
            "receive-%s" % codes.NOTIFICATION.SHORT: "notification",
            "receive-%s" % codes.OPEN.SHORT: "open",
            "receive-%s" % codes.KEEPALIVE.SHORT: "keepalive",
            "receive-%s" % codes.UPDATE.SHORT: "update",
            "receive-%s" % codes.ROUTE_REFRESH.SHORT: "refresh",
            "receive-%s" % codes.OPERATIONAL.SHORT: "operational",
        }

        _extension_send = {
            "send-packets": "packets",
            "send-parsed": "parsed",
            "send-consolidate": "consolidate",
            "send-%s" % codes.NOTIFICATION.SHORT: "notification",
            "send-%s" % codes.OPEN.SHORT: "open",
            "send-%s" % codes.KEEPALIVE.SHORT: "keepalive",
            "send-%s" % codes.UPDATE.SHORT: "update",
            "send-%s" % codes.ROUTE_REFRESH.SHORT: "refresh",
            "send-%s" % codes.OPERATIONAL.SHORT: "operational",
        }

        _receive = []
        for api, name in _extension_receive.items():
            _receive.extend(["\t\t\t%s;\n" % name] if self.api[api] else [])
        receive = "".join(_receive)

        _send = []
        for api, name in _extension_send.items():
            _send.extend(["\t\t\t%s;\n" % name] if self.api[api] else [])
        send = "".join(_send)

        returned = (
            "neighbor %s {\n"
            '\tdescription "%s";\n'
            "\trouter-id %s;\n"
            "\thost-name %s;\n"
            "\tdomain-name %s;\n"
            "\tlocal-address %s;\n"
            "\tlocal-as %s;\n"
            "\tpeer-as %s;\n"
            "\thold-time %s;\n"
            "\tmanual-eor %s;\n"
            "%s%s%s%s%s%s%s\n"
            "\tcapability {\n"
            "%s%s%s%s%s%s%s\t}\n"
            "\tfamily {%s\n"
            "\t}\n"
            "\tprocess {\n"
            "%s%s\t}%s\n"
            "}"
            % (
                self.peer_address,
                self.description,
                self.router_id,
                self.host_name,
                self.domain_name,
                self.local_address,
                self.local_as,
                self.peer_as,
                self.hold_time,
                "true" if self.manual_eor else "false",
                "\n\tpassive;\n" if self.passive else "",
                "\n\tlisten %d;\n" % self.listen if self.listen else "",
                "\tgroup-updates: %s;\n" % (self.group_updates if self.group_updates else ""),
                "\tauto-flush: %s;\n" % ("true" if self.flush else "false"),
                "\tadj-rib-out: %s;\n" % ("true" if self.adjribout else "false"),
                '\tmd5 "%s";\n' % self.md5 if self.md5 else "",
                "\tttl-security: %s;\n" % (self.ttl if self.ttl else ""),
                "\t\tasn4 %s;\n" % ("enable" if self.asn4 else "disable"),
                "\t\troute-refresh %s;\n" % ("enable" if self.route_refresh else "disable"),
                "\t\tgraceful-restart %s;\n" % (self.graceful_restart if self.graceful_restart else "disable"),
                "\t\tadd-path %s;\n" % (AddPath.string[self.add_path] if self.add_path else "disable"),
                "\t\tmulti-session %s;\n" % ("enable" if self.multisession else "disable"),
                "\t\toperational %s;\n" % ("enable" if self.operational else "disable"),
                "\t\taigp %s;\n" % ("enable" if self.aigp else "disable"),
                families,
                "\t\treceive {\n%s\t\t}\n" % receive if receive else "",
                "\t\tsend {\n%s\t\t}\n" % send if send else "",
                changes,
            )
        )
        return returned.replace("\t", "  ")

    def __str__(self):
        return self.pprint(False)
예제 #5
0
class Neighbor (object):
    _GLOBAL = {'uid': 1}

    def __init__ (self):
        # self.logger should not be used here as long as we do use deepcopy as it contains a Lock
        self.description = None
        self.router_id = None
        self.host_name = None
        self.domain_name = None
        self.local_address = None
        self.range_size = 1
        # local_address uses auto discovery
        self.auto_discovery = False
        self.peer_address = None
        self.peer_as = None
        self.local_as = None
        self.hold_time = None
        self.asn4 = None
        self.nexthop = None
        self.add_path = None
        self.md5_password = None
        self.md5_base64 = False
        self.md5_ip = None
        self.ttl_in = None
        self.ttl_out = None
        self.group_updates = None
        self.flush = None
        self.adj_rib_in = None
        self.adj_rib_out = None

        self.manual_eor = False

        self.api = None  # XXX: not scriptable - is replaced outside the class
        # passive indicate that we do not establish outgoing connections
        self.passive = False
        # the port to listen on ( zero mean that we do not listen )
        self.listen = 0
        # the port to connect to
        self.connect = 0

        # was this Neighbor generated from a range
        self.generated = False

        # capability
        self.route_refresh = False
        self.graceful_restart = False
        self.multisession = None
        self.nexthop = None
        self.add_path = None
        self.aigp = None

        self._families = []
        self._nexthop = []
        self._addpath = []
        self.rib = None

        # The routes we have parsed from the configuration
        self.changes = []
        # On signal update, the previous routes so we can compare what changed
        self.backup_changes = []

        self.operational = None
        self.eor = deque()
        self.asm = dict()

        self.messages = deque()
        self.refresh = deque()

        self.counter = Counter()

        self.ski = []
        self.bgpsec_openssl_lib = []
        self.bgpsec_crypto_init = []
        self.bgpsec_pre_asns = []
        self.bgpsec_pre_skis = []
        self.bgpsec_send_receive = []
        # It is possible to :
        # - have multiple exabgp toward one peer on the same host ( use of pid )
        # - have more than once connection toward a peer
        # - each connection has it own neihgbor (hence why identificator is not in Protocol)
        self.uid = '%d' % self._GLOBAL['uid']
        self._GLOBAL['uid'] += 1

    def id (self):
        return 'neighbor-%s' % self.uid

    def make_rib (self):
        self.rib = RIB(self.name(),self.adj_rib_in,self.adj_rib_out,self._families)

    # will resend all the routes once we reconnect
    def reset_rib (self):
        self.rib.reset()
        self.messages = deque()
        self.refresh = deque()

    # back to square one, all the routes are removed
    def clear_rib (self):
        self.rib.clear()
        self.messages = deque()
        self.refresh = deque()

    def name (self):
        if self.multisession:
            session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
        else:
            session = 'in-open'
        return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (
            self.peer_address,
            self.local_address if self.peer_address is not None else 'auto',
            self.local_as if self.local_as is not None else 'auto',
            self.peer_as if self.peer_as is not None else 'auto',
            self.router_id,
            session
        )

    def families (self):
        # this list() is important .. as we use the function to modify self._families
        return list(self._families)

    def nexthops (self):
        # this list() is important .. as we use the function to modify self._nexthop
        return list(self._nexthop)

    def addpaths (self):
        # this list() is important .. as we use the function to modify self._add_path
        return list(self._addpath)

    def add_family (self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        # this list() is important .. as we use the function to modify self._families
        if family not in self.families():
            afi,safi = family
            d = dict()
            d[afi] = [safi,]
            for afi,safi in self._families:
                d.setdefault(afi,[]).append(safi)
            self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

    def add_nexthop (self, afi, safi, nhafi):
        if (afi,safi,nhafi) not in self._nexthop:
            self._nexthop.append((afi,safi,nhafi))

    def add_addpath (self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        # this list() is important .. as we use the function to modify self._add_path
        if family not in self.addpaths():
            afi,safi = family
            d = dict()
            d[afi] = [safi,]
            for afi,safi in self._addpath:
                d.setdefault(afi,[]).append(safi)
            self._addpath = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

    def remove_family (self, family):
        if family in self.families():
            self._families.remove(family)

    def remove_nexthop (self, afi, safi, nhafi):
        if (afi,safi,nhafi) in self.nexthops():
            self._nexthop.remove((afi,safi,nhafi))

    def remove_addpath (self, family):
        if family in self.addpaths():
            self._addpath.remove(family)

    def missing (self):
        if self.local_address is None and not self.auto_discovery:
            return 'local-address'
        if self.listen > 0 and self.auto_discovery:
            return 'local-address'
        if self.peer_address is None:
            return 'peer-address'
        if self.auto_discovery and not self.router_id:
            return 'router-id'
        if self.peer_address.afi == AFI.ipv6 and not self.router_id:
            return 'router-id'
        return ''

    # This function only compares the neighbor BUT NOT ITS ROUTES
    def __eq__ (self, other):
        # Comparing local_address is skipped in the case where either
        # peer is configured to auto discover its local address. In
        # this case it can happen that one local_address is None and
        # the other one will be set to the auto disocvered IP address.
        auto_discovery = self.auto_discovery or other.auto_discovery
        return \
            self.router_id == other.router_id and \
            (auto_discovery or self.local_address == other.local_address) and \
            self.auto_discovery == other.auto_discovery and \
            self.local_as == other.local_as and \
            self.peer_address == other.peer_address and \
            self.peer_as == other.peer_as and \
            self.passive == other.passive and \
            self.listen == other.listen and \
            self.connect == other.connect and \
            self.hold_time == other.hold_time and \
            self.host_name == other.host_name and \
            self.domain_name == other.domain_name and \
            self.md5_password == other.md5_password and \
            self.md5_ip == other.md5_ip and \
            self.ttl_in == other.ttl_in and \
            self.ttl_out == other.ttl_out and \
            self.route_refresh == other.route_refresh and \
            self.graceful_restart == other.graceful_restart and \
            self.multisession == other.multisession and \
            self.nexthop == other.nexthop and \
            self.add_path == other.add_path and \
            self.operational == other.operational and \
            self.group_updates == other.group_updates and \
            self.flush == other.flush and \
            self.adj_rib_in == other.adj_rib_in and \
            self.adj_rib_out == other.adj_rib_out and \
            self.families() == other.families()

    def __ne__ (self, other):
        return not self.__eq__(other)

    def string (self, with_changes=True):
        changes = ''
        if with_changes:
            changes += '\nstatic { '
            for changes in self.rib.incoming.queued_changes():
                changes += '\n\t\t%s' % changes.extensive()
            changes += '\n}'

        families = ''
        for afi,safi in self.families():
            families += '\n\t\t%s %s;' % (afi.name(),safi.name())

        nexthops = ''
        for afi, safi, nexthop in self.nexthops():
            nexthops += '\n\t\t%s %s %s;' % (afi.name(), safi.name(), nexthop.name())

        addpaths = ''
        for afi,safi in self.addpaths():
            addpaths += '\n\t\t%s %s;' % (afi.name(),safi.name())

        codes = Message.CODE

        _extension_global = {
            'neighbor-changes': 'neighbor-changes',
            'negotiated':       'negotiated',
            'fsm':              'fsm',
            'signal':           'signal',
        }

        _extension_receive = {
            'receive-packets':                        'packets',
            'receive-parsed':                         'parsed',
            'receive-consolidate':                    'consolidate',
            'receive-%s' % codes.NOTIFICATION.SHORT:  'notification',
            'receive-%s' % codes.OPEN.SHORT:          'open',
            'receive-%s' % codes.KEEPALIVE.SHORT:     'keepalive',
            'receive-%s' % codes.UPDATE.SHORT:        'update',
            'receive-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh',
            'receive-%s' % codes.OPERATIONAL.SHORT:   'operational',
        }

        _extension_send = {
            'send-packets':                        'packets',
            'send-parsed':                         'parsed',
            'send-consolidate':                    'consolidate',
            'send-%s' % codes.NOTIFICATION.SHORT:  'notification',
            'send-%s' % codes.OPEN.SHORT:          'open',
            'send-%s' % codes.KEEPALIVE.SHORT:     'keepalive',
            'send-%s' % codes.UPDATE.SHORT:        'update',
            'send-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh',
            'send-%s' % codes.OPERATIONAL.SHORT:   'operational',
        }

        apis = ''

        for process in self.api.get('processes',[]):
            _global = []
            _receive = []
            _send = []

            for api,name in _extension_global.items():
                _global.extend(['\t\t%s;\n' % name,] if process in self.api[api] else [])

            for api,name in _extension_receive.items():
                _receive.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else [])

            for api,name in _extension_send.items():
                _send.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else [])

            _api  = '\tapi {\n'
            _api += '\t\tprocesses [ %s ];\n' % process
            _api += ''.join(_global)
            if _receive:
                _api += '\t\treceive {\n'
                _api += ''.join(_receive)
                _api += '\t\t}\n'
            if _send:
                _api += '\t\tsend {\n'
                _api += ''.join(_send)
                _api += '\t\t}\n'
            _api += '\t}\n'

            apis += _api

        returned = \
            'neighbor %s {\n' \
            '\tdescription "%s";\n' \
            '\trouter-id %s;\n' \
            '\thost-name %s;\n' \
            '\tdomain-name %s;\n' \
            '\tlocal-address %s;\n' \
            '\tlocal-as %s;\n' \
            '\tpeer-as %s;\n' \
            '\thold-time %s;\n' \
            '\tmanual-eor %s;\n' \
            '%s%s%s%s%s%s%s%s%s%s%s\n' \
            '\tcapability {\n' \
            '%s%s%s%s%s%s%s%s%s\t}\n' \
            '\tfamily {%s\n' \
            '\t}\n' \
            '\tnexthop {%s\n' \
            '\t}\n' \
            '\tadd-path {%s\n' \
            '\t}\n' \
            '%s' \
            '%s' \
            '}' % (
                self.peer_address,
                self.description,
                self.router_id,
                self.host_name,
                self.domain_name,
                self.local_address if not self.auto_discovery else 'auto',
                self.local_as,
                self.peer_as,
                self.hold_time,
                'true' if self.manual_eor else 'false',
                '\n\tpassive %s;\n' % ('true' if self.passive else 'false'),
                '\n\tlisten %d;\n' % self.listen if self.listen else '',
                '\n\tconnect %d;\n' % self.connect if self.connect else '',
                '\tgroup-updates %s;\n' % ('true' if self.group_updates else 'false'),
                '\tauto-flush %s;\n' % ('true' if self.flush else 'false'),
                '\tadj-rib-in %s;\n' % ('true' if self.adj_rib_in else 'false'),
                '\tadj-rib-out %s;\n' % ('true' if self.adj_rib_out else 'false'),
                '\tmd5-password "%s";\n' % self.md5_password if self.md5_password else '',
                '\tmd5-base64 %s;\n' % ('true' if self.md5_base64 is True else 'false' if self.md5_base64 is False else 'auto'),
                '\tmd5-ip "%s";\n' % self.md5_ip if not self.auto_discovery else '',
                '\toutgoing-ttl %s;\n' % self.ttl_out if self.ttl_out else '',
                '\tincoming-ttl %s;\n' % self.ttl_in if self.ttl_in else '',
                '\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'),
                '\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'),
                '\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'),
                '\t\tnexthop %s;\n' % ('enable' if self.nexthop else 'disable'),
                '\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'),
                '\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'),
                '\t\toperational %s;\n' % ('enable' if self.operational else 'disable'),
                '\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'),
                families,
                nexthops,
                addpaths,
                apis,
                changes
            )

        # '\t\treceive {\n%s\t\t}\n' % receive if receive else '',
        # '\t\tsend {\n%s\t\t}\n' % send if send else '',
        return returned.replace('\t','  ')

    def __str__ (self):
        return self.string(False)
예제 #6
0
파일: neighbor.py 프로젝트: pierky/exabgp
class Neighbor(dict):
    class Capability(dict):
        defaults = {
            'asn4': True,
            'extended-message': True,
            'graceful-restart': False,
            'multi-session': False,
            'operational': False,
            'add-path': 0,
            'route-refresh': 0,
            'nexthop': None,
            'aigp': None,
        }

    defaults = {
        # Those are the field from the configuration
        'description': '',
        'router-id': None,
        'local-address': None,
        'peer-address': None,
        'local-as': None,
        'peer-as': None,
        # passive indicate that we do not establish outgoing connections
        'passive': False,
        # the port to listen on ( zero mean that we do not listen )
        'listen': 0,
        # the port to connect to
        'connect': 0,
        'hold-time': HoldTime(180),
        'rate-limit': 0,
        'host-name': host(),
        'domain-name': domain(),
        'group-updates': True,
        'auto-flush': True,
        'adj-rib-in': True,
        'adj-rib-out': True,
        'manual-eor': False,
        # XXX: this should be under an MD5 sub-dict/object ?
        'md5-password': None,
        'md5-base64': False,
        'md5-ip': None,
        'outgoing-ttl': None,
        'incoming-ttl': None,
    }

    _GLOBAL = {'uid': 1}

    def __init__(self):
        # super init
        self.update(self.defaults)

        # Those are subconf
        self.api = None  # XXX: not scriptable - is replaced outside the class

        # internal or calculated field
        self['capability'] = self.Capability.defaults.copy()

        # local_address uses auto discovery
        self.auto_discovery = False

        self.range_size = 1

        # was this Neighbor generated from a range
        self.generated = False

        self._families = []
        self._nexthop = []
        self._addpath = []
        self.rib = None

        # The routes we have parsed from the configuration
        self.changes = []
        # On signal update, the previous routes so we can compare what changed
        self.backup_changes = []

        self.eor = deque()
        self.asm = dict()

        self.messages = deque()
        self.refresh = deque()

        self.counter = Counter()
        # It is possible to :
        # - have multiple exabgp toward one peer on the same host ( use of pid )
        # - have more than once connection toward a peer
        # - each connection has it own neihgbor (hence why identificator is not in Protocol)
        self.uid = '%d' % self._GLOBAL['uid']
        self._GLOBAL['uid'] += 1

    def missing(self):
        if self['local-as'] is None:
            return 'incomplete neighbor, missing local-address'
        if self['local-as'] is None:
            return 'incomplete neighbor, missing local-as'
        if self['peer-as'] is None:
            return 'incomplete neighbor, missing peer-as'
        return ''

    def infer(self):
        if self['md5-ip'] is None:
            self['md5-ip'] = self['local-address']

        if self['capability']['graceful-restart'] == 0:
            self['capability']['graceful-restart'] = int(self['hold-time'])

    def id(self):
        return 'neighbor-%s' % self.uid

    # This set must be unique between peer, not full draft-ietf-idr-bgp-multisession-07
    def index(self):
        if self['listen'] != 0:
            return 'peer-ip %s listen %d' % (self['peer-address'],
                                             self['listen'])
        return self.name()

    def make_rib(self):
        self.rib = RIB(self.name(), self['adj-rib-in'], self['adj-rib-out'],
                       self._families)

    # will resend all the routes once we reconnect
    def reset_rib(self):
        self.rib.reset()
        self.messages = deque()
        self.refresh = deque()

    # back to square one, all the routes are removed
    def clear_rib(self):
        self.rib.clear()
        self.messages = deque()
        self.refresh = deque()

    def name(self):
        if self['capability']['multi-session']:
            session = '/'.join("%s-%s" % (afi.name(), safi.name())
                               for (afi, safi) in self.families())
        else:
            session = 'in-open'
        return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (
            self['peer-address'],
            self['local-address']
            if self['peer-address'] is not None else 'auto',
            self['local-as'] if self['local-as'] is not None else 'auto',
            self['peer-as'] if self['peer-as'] is not None else 'auto',
            self['router-id'],
            session,
        )

    def families(self):
        # this list() is important .. as we use the function to modify self._families
        return list(self._families)

    def nexthops(self):
        # this list() is important .. as we use the function to modify self._nexthop
        return list(self._nexthop)

    def addpaths(self):
        # this list() is important .. as we use the function to modify self._add_path
        return list(self._addpath)

    def add_family(self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        # this list() is important .. as we use the function to modify self._families
        if family not in self.families():
            afi, safi = family
            d = dict()
            d[afi] = [
                safi,
            ]
            for afi, safi in self._families:
                d.setdefault(afi, []).append(safi)
            self._families = [(afi, safi) for afi in sorted(d)
                              for safi in sorted(d[afi])]

    def add_nexthop(self, afi, safi, nhafi):
        if (afi, safi, nhafi) not in self._nexthop:
            self._nexthop.append((afi, safi, nhafi))

    def add_addpath(self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        # this list() is important .. as we use the function to modify self._add_path
        if family not in self.addpaths():
            afi, safi = family
            d = dict()
            d[afi] = [
                safi,
            ]
            for afi, safi in self._addpath:
                d.setdefault(afi, []).append(safi)
            self._addpath = [(afi, safi) for afi in sorted(d)
                             for safi in sorted(d[afi])]

    def remove_family(self, family):
        if family in self.families():
            self._families.remove(family)

    def remove_nexthop(self, afi, safi, nhafi):
        if (afi, safi, nhafi) in self.nexthops():
            self._nexthop.remove((afi, safi, nhafi))

    def remove_addpath(self, family):
        if family in self.addpaths():
            self._addpath.remove(family)

    def missing(self):
        if self['local-address'] is None and not self.auto_discovery:
            return 'local-address'
        if self['listen'] > 0 and self.auto_discovery:
            return 'local-address'
        if self['peer-address'] is None:
            return 'peer-address'
        if self.auto_discovery and not self['router-id']:
            return 'router-id'
        if self['peer-address'].afi == AFI.ipv6 and not self['router-id']:
            return 'router-id'
        return ''

    # This function only compares the neighbor BUT NOT ITS ROUTES
    def __eq__(self, other):
        # Comparing local_address is skipped in the case where either
        # peer is configured to auto discover its local address. In
        # this case it can happen that one local_address is None and
        # the other one will be set to the auto disocvered IP address.
        auto_discovery = self.auto_discovery or other.auto_discovery
        return (self['router-id'] == other['router-id']
                and self['local-as'] == other['local-as']
                and self['peer-address'] == other['peer-address']
                and self['peer-as'] == other['peer-as']
                and self['passive'] == other['passive']
                and self['listen'] == other['listen']
                and self['connect'] == other['connect']
                and self['hold-time'] == other['hold-time']
                and self['rate-limit'] == other['rate-limit']
                and self['host-name'] == other['host-name']
                and self['domain-name'] == other['domain-name']
                and self['md5-password'] == other['md5-password']
                and self['md5-ip'] == other['md5-ip']
                and self['incoming-ttl'] == other['incoming-ttl']
                and self['outgoing-ttl'] == other['outgoing-ttl']
                and self['group-updates'] == other['group-updates']
                and self['auto-flush'] == other['auto-flush']
                and self['adj-rib-in'] == other['adj-rib-in']
                and self['adj-rib-out'] == other['adj-rib-out']
                and (auto_discovery
                     or self['local-address'] == other['local-address'])
                and self['capability'] == other['capability']
                and self.auto_discovery == other.auto_discovery
                and self.families() == other.families())

    def __ne__(self, other):
        return not self.__eq__(other)

    def string(self, with_changes=True):
        changes = ''
        if with_changes:
            changes += '\nstatic { '
            for change in self.rib.outgoing.queued_changes():
                changes += '\n\t\t%s' % change.extensive()
            changes += '\n}'

        families = ''
        for afi, safi in self.families():
            families += '\n\t\t%s %s;' % (afi.name(), safi.name())

        nexthops = ''
        for afi, safi, nexthop in self.nexthops():
            nexthops += '\n\t\t%s %s %s;' % (afi.name(), safi.name(),
                                             nexthop.name())

        addpaths = ''
        for afi, safi in self.addpaths():
            addpaths += '\n\t\t%s %s;' % (afi.name(), safi.name())

        codes = Message.CODE

        _extension_global = {
            'neighbor-changes': 'neighbor-changes',
            'negotiated': 'negotiated',
            'fsm': 'fsm',
            'signal': 'signal',
        }

        _extension_receive = {
            'receive-packets': 'packets',
            'receive-parsed': 'parsed',
            'receive-consolidate': 'consolidate',
            'receive-%s' % codes.NOTIFICATION.SHORT: 'notification',
            'receive-%s' % codes.OPEN.SHORT: 'open',
            'receive-%s' % codes.KEEPALIVE.SHORT: 'keepalive',
            'receive-%s' % codes.UPDATE.SHORT: 'update',
            'receive-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh',
            'receive-%s' % codes.OPERATIONAL.SHORT: 'operational',
        }

        _extension_send = {
            'send-packets': 'packets',
            'send-parsed': 'parsed',
            'send-consolidate': 'consolidate',
            'send-%s' % codes.NOTIFICATION.SHORT: 'notification',
            'send-%s' % codes.OPEN.SHORT: 'open',
            'send-%s' % codes.KEEPALIVE.SHORT: 'keepalive',
            'send-%s' % codes.UPDATE.SHORT: 'update',
            'send-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh',
            'send-%s' % codes.OPERATIONAL.SHORT: 'operational',
        }

        apis = ''

        for process in self.api.get('processes', []):
            _global = []
            _receive = []
            _send = []

            for api, name in _extension_global.items():
                _global.extend([
                    '\t\t%s;\n' % name,
                ] if process in self.api[api] else [])

            for api, name in _extension_receive.items():
                _receive.extend([
                    '\t\t\t%s;\n' % name,
                ] if process in self.api[api] else [])

            for api, name in _extension_send.items():
                _send.extend([
                    '\t\t\t%s;\n' % name,
                ] if process in self.api[api] else [])

            _api = '\tapi {\n'
            _api += '\t\tprocesses [ %s ];\n' % process
            _api += ''.join(_global)
            if _receive:
                _api += '\t\treceive {\n'
                _api += ''.join(_receive)
                _api += '\t\t}\n'
            if _send:
                _api += '\t\tsend {\n'
                _api += ''.join(_send)
                _api += '\t\t}\n'
            _api += '\t}\n'

            apis += _api

        returned = (
            'neighbor %s {\n'
            '\tdescription "%s";\n'
            '\trouter-id %s;\n'
            '\thost-name %s;\n'
            '\tdomain-name %s;\n'
            '\tlocal-address %s;\n'
            '\tlocal-as %s;\n'
            '\tpeer-as %s;\n'
            '\thold-time %s;\n'
            '\trate-limit %s;\n'
            '\tmanual-eor %s;\n'
            '%s%s%s%s%s%s%s%s%s%s%s\n'
            '\tcapability {\n'
            '%s%s%s%s%s%s%s%s%s\t}\n'
            '\tfamily {%s\n'
            '\t}\n'
            '\tnexthop {%s\n'
            '\t}\n'
            '\tadd-path {%s\n'
            '\t}\n'
            '%s'
            '%s'
            '}' % (
                self['peer-address'],
                self['description'],
                self['router-id'],
                self['host-name'],
                self['domain-name'],
                self['local-address'] if not self.auto_discovery else 'auto',
                self['local-as'],
                self['peer-as'],
                self['hold-time'],
                'disable' if self['rate-limit'] == 0 else self['rate-limit'],
                'true' if self['manual-eor'] else 'false',
                '\n\tpassive %s;\n' % ('true' if self['passive'] else 'false'),
                '\n\tlisten %d;\n' % self['listen'] if self['listen'] else '',
                '\n\tconnect %d;\n' %
                self['connect'] if self['connect'] else '',
                '\tgroup-updates %s;\n' %
                ('true' if self['group-updates'] else 'false'),
                '\tauto-flush %s;\n' %
                ('true' if self['auto-flush'] else 'false'),
                '\tadj-rib-in %s;\n' %
                ('true' if self['adj-rib-in'] else 'false'),
                '\tadj-rib-out %s;\n' %
                ('true' if self['adj-rib-out'] else 'false'),
                '\tmd5-password "%s";\n' %
                self['md5-password'] if self['md5-password'] else '',
                '\tmd5-base64 %s;\n' %
                ('true' if self['md5-base64'] is True else
                 'false' if self['md5-base64'] is False else 'auto'),
                '\tmd5-ip "%s";\n' %
                self['md5-ip'] if not self.auto_discovery else '',
                '\toutgoing-ttl %s;\n' %
                self['outgoing-ttl'] if self['outgoing-ttl'] else '',
                '\tincoming-ttl %s;\n' %
                self['incoming-ttl'] if self['incoming-ttl'] else '',
                '\t\tasn4 %s;\n' %
                ('enable' if self['capability']['asn4'] else 'disable'),
                '\t\troute-refresh %s;\n' %
                ('enable'
                 if self['capability']['route-refresh'] else 'disable'),
                '\t\tgraceful-restart %s;\n' %
                (self['capability']['graceful-restart']
                 if self['capability']['graceful-restart'] else 'disable'),
                '\t\tnexthop %s;\n' %
                ('enable' if self['capability']['nexthop'] else 'disable'),
                '\t\tadd-path %s;\n' %
                (AddPath.string[self['capability']['add-path']]
                 if self['capability']['add-path'] else 'disable'),
                '\t\tmulti-session %s;\n' %
                ('enable'
                 if self['capability']['multi-session'] else 'disable'),
                '\t\toperational %s;\n' %
                ('enable' if self['capability']['operational'] else 'disable'),
                '\t\taigp %s;\n' %
                ('enable' if self['capability']['aigp'] else 'disable'),
                families,
                nexthops,
                addpaths,
                apis,
                changes,
            ))

        # '\t\treceive {\n%s\t\t}\n' % receive if receive else '',
        # '\t\tsend {\n%s\t\t}\n' % send if send else '',
        return returned.replace('\t', '  ')

    def __str__(self):
        return self.string(False)
예제 #7
0
class Neighbor (object):
	def __init__ (self):
		# self.logger should not be used here as long as we do use deepcopy as it contains a Lock
		self.description = ''
		self.router_id = None
		self.local_address = None
		self.peer_address = None
		self.peer_as = None
		self.local_as = None
		self.hold_time = HoldTime(180)
		self.asn4 = None
		self.add_path = 0
		self.md5 = None
		self.ttl = None
		self.group_updates = None
		self.flush = None
		self.adjribout = None

		self.api = APIOptions()

		self.passive = False

		# capability
		self.route_refresh = False
		self.graceful_restart = False
		self.multisession = None
		self.add_path = None
		self.aigp = None

		self._families = []
		self.rib = None

		self.operational = None
		self.eor = deque()
		self.asm = dict()

		self.messages = deque()
		self.refresh = deque()


	def identificator (self):
		# It is possible to :
		# - have multiple exabgp toward one peer on the same host ( use of pid )
		# - have more than once connection toward a peer
		# - each connection has it own neihgbor (hence why identificator is not in Protocol)
		return str(self.peer_address)

	def make_rib (self):
		self.rib = RIB(self.name(),self.adjribout,self._families)

	# will resend all the routes once we reconnect
	def reset_rib (self):
		self.rib.reset()
		self.messages = deque()
		self.refresh = deque()

	# back to square one, all the routes are removed
	def clear_rib (self):
		self.rib.clear()
		self.messages = deque()
		self.refresh = deque()

	def name (self):
		if self.multisession:
			session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
		else:
			session = 'in-open'
		return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (self.peer_address,self.local_address,self.local_as,self.peer_as,self.router_id,session)

	def families (self):
		# this list() is important .. as we use the function to modify self._families
		return list(self._families)

	def add_family (self,family):
		# the families MUST be sorted for neighbor indexing name to be predictable for API users
		if not family in self.families():
			afi,safi = family
			d = dict()
			d[afi] = [safi,]
			for afi,safi in self._families:
				d.setdefault(afi,[]).append(safi)
			self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

	def remove_family (self,family):
		if family in self.families():
			self._families.remove(family)

	def missing (self):
		if self.local_address is None: return 'local-address'
		if self.peer_address is None: return 'peer-address'
		if self.local_as is None: return 'local-as'
		if self.peer_as is None: return 'peer-as'
		if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id'
		return ''

	# This function only compares the neighbor BUT NOT ITS ROUTES
	def __eq__ (self,other):
		return \
			self.router_id == other.router_id and \
			self.local_address == other.local_address and \
			self.local_as == other.local_as and \
			self.peer_address == other.peer_address and \
			self.peer_as == other.peer_as and \
			self.passive == other.passive and \
			self.hold_time == other.hold_time and \
			self.md5 == other.md5 and \
			self.ttl == other.ttl and \
			self.route_refresh == other.route_refresh and \
			self.graceful_restart == other.graceful_restart and \
			self.multisession == other.multisession and \
			self.add_path == other.add_path and \
			self.operational == other.operational and \
			self.group_updates == other.group_updates and \
			self.flush == other.flush and \
			self.adjribout == other.adjribout and \
			self.families() == other.families()

	def __ne__(self, other):
		return not self.__eq__(other)

	def pprint (self,with_changes=True):
		changes=''
		if with_changes:
			changes += '\nstatic { '
			for changes in self.rib.incoming.queued_changes():
				changes += '\n    %s' % changes.extensive()
			changes += '\n}'

		families = ''
		for afi,safi in self.families():
			families += '\n    %s %s;' % (afi.name(),safi.name())

		_receive  = []

		_receive.extend(['      parsed;\n',]           if self.api['receive-parsed'] else [])
		_receive.extend(['      packets;\n',]          if self.api['receive-packets'] else [])
		_receive.extend(['      consolidate;\n',]      if self.api['consolidate'] else [])

		_receive.extend(['      neighbor-changes;\n',] if self.api['neighbor-changes'] else [])
		_receive.extend(['      notification;\n',]     if self.api[Message.ID.NOTIFICATION] else [])
		_receive.extend(['      open;\n',]             if self.api[Message.ID.OPEN] else [])
		_receive.extend(['      keepalive;\n',]        if self.api[Message.ID.KEEPALIVE] else [])
		_receive.extend(['      update;\n',]           if self.api[Message.ID.UPDATE] else [])
		_receive.extend(['      refresh;\n',]          if self.api[Message.ID.ROUTE_REFRESH] else [])
		_receive.extend(['      operational;\n',]      if self.api[Message.ID.OPERATIONAL] else [])
		_receive.extend(['      parsed;\n',]           if self.api['receive-parsed'] else [])
		_receive.extend(['      packets;\n',]          if self.api['receive-packets'] else [])
		_receive.extend(['      consolidate;\n',]      if self.api['consolidate'] else [])

		receive = ''.join(_receive)

		_send = []
		_send.extend(['      packets;\n',]          if self.api['send-packets'] else [])
		send = ''.join(_send)

		return """\
neighbor %s {
  description "%s";
  router-id %s;
  local-address %s;
  local-as %s;
  peer-as %s;%s
  hold-time %s;
%s%s%s%s%s
  capability {
%s%s%s%s%s%s%s  }
  family {%s
  }
  process {
%s%s  }%s
}""" % (
	self.peer_address,
	self.description,
	self.router_id,
	self.local_address,
	self.local_as,
	self.peer_as,
	'\n  passive;\n' if self.passive else '',
	self.hold_time,
	'  group-updates: %s;\n' % (self.group_updates if self.group_updates else ''),
	'  auto-flush: %s;\n' % ('true' if self.flush else 'false'),
	'  adj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'),
	'  md5 "%s";\n' % self.md5 if self.md5 else '',
	'  ttl-security: %s;\n' % (self.ttl if self.ttl else ''),
	'    asn4 %s;\n' % ('enable' if self.asn4 else 'disable'),
	'    route-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'),
	'    graceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'),
	'    add-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'),
	'    multi-session %s;\n' % ('enable' if self.multisession else 'disable'),
	'    operational %s;\n' % ('enable' if self.operational else 'disable'),
	'    aigp %s;\n' % ('enable' if self.aigp else 'disable'),
	families,
	'    receive {\n%s    }\n' % receive if receive else '',
	'    send {\n%s    }\n' % send if send else '',
	changes
)

	def __str__ (self):
		return self.pprint(False)
예제 #8
0
class Neighbor (object):
	def __init__ (self):
		# self.logger should not be used here as long as we do use deepcopy as it contains a Lock
		self.description = ''
		self.router_id = None
		self.local_address = None
		self.peer_address = None
		self.peer_as = None
		self.local_as = None
		self.hold_time = HoldTime(180)
		self.asn4 = None
		self.add_path = 0
		self.md5 = None
		self.ttl = None
		self.group_updates = None
		self.flush = None
		self.adjribout = None

		self.api = APIOptions()

		self.passive = False

		# capability
		self.route_refresh = False
		self.graceful_restart = False
		self.multisession = None
		self.add_path = None
		self.aigp = None

		self._families = []
		self.rib = None

		self.operational = None
		self.asm = dict()

		self.messages = deque()
		self.refresh = deque()

	def make_rib (self):
		self.rib = RIB(self.name(),self.adjribout,self._families)

	# will resend all the routes once we reconnect
	def reset_rib (self):
		self.rib.reset()
		self.messages = deque()
		self.refresh = deque()

	# back to square one, all the routes are removed
	def clear_rib (self):
		self.rib.clear()
		self.messages = deque()
		self.refresh = deque()

	def name (self):
		if self.multisession:
			session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
		else:
			session = 'in-open'
		return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (self.peer_address,self.local_address,self.local_as,self.peer_as,self.router_id,session)

	def families (self):
		# this list() is important .. as we use the function to modify self._families
		return list(self._families)

	def add_family (self,family):
		# the families MUST be sorted for neighbor indexing name to be predictable for API users
		if not family in self.families():
			afi,safi = family
			d = dict()
			d[afi] = [safi,]
			for afi,safi in self._families:
				d.setdefault(afi,[]).append(safi)
			self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

	def remove_family (self,family):
		if family in self.families():
			self._families.remove(family)

	def missing (self):
		if self.local_address is None: return 'local-address'
		if self.peer_address is None: return 'peer-address'
		if self.local_as is None: return 'local-as'
		if self.peer_as is None: return 'peer-as'
		if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id'
		return ''

	# This function only compares the neighbor BUT NOT ITS ROUTES
	def __eq__ (self,other):
		return \
			self.router_id == other.router_id and \
			self.local_address == other.local_address and \
			self.local_as == other.local_as and \
			self.peer_address == other.peer_address and \
			self.peer_as == other.peer_as and \
			self.passive == other.passive and \
			self.hold_time == other.hold_time and \
			self.md5 == other.md5 and \
			self.ttl == other.ttl and \
			self.route_refresh == other.route_refresh and \
			self.graceful_restart == other.graceful_restart and \
			self.multisession == other.multisession and \
			self.add_path == other.add_path and \
			self.operational == other.operational and \
			self.group_updates == other.group_updates and \
			self.flush == other.flush and \
			self.adjribout == other.adjribout and \
			self.families() == other.families()

	def __ne__(self, other):
		return not self.__eq__(other)

	def pprint (self,with_changes=True):
		changes=''
		if with_changes:
			changes += '\nstatic { '
			for changes in self.rib.incoming.queued_changes():
				changes += '\n    %s' % changes.extensive()
			changes += '\n}'

		families = ''
		for afi,safi in self.families():
			families += '\n    %s %s;' % (afi.name(),safi.name())

		_api  = []
		_api.extend(['    neighbor-changes;\n',]    if self.api.neighbor_changes else [])
		_api.extend(['    receive-packets;\n',]     if self.api.receive_packets else [])
		_api.extend(['    send-packets;\n',]        if self.api.send_packets else [])
		_api.extend(['    receive-routes;\n',]      if self.api.receive_routes else [])
		_api.extend(['    receive-operational;\n',] if self.api.receive_operational else [])
		api = ''.join(_api)

		return """\
neighbor %s {
  description "%s";
  router-id %s;
  local-address %s;
  local-as %s;
  peer-as %s;%s
  hold-time %s;
%s%s%s%s%s
  capability {
%s%s%s%s%s%s%s  }
  family {%s
  }
  process {
%s  }%s
}""" % (
	self.peer_address,
	self.description,
	self.router_id,
	self.local_address,
	self.local_as,
	self.peer_as,
	'\n  passive;\n' if self.passive else '',
	self.hold_time,
	'  group-updates: %s;\n' % self.group_updates if self.group_updates else '',
	'  auto-flush: %s;\n' % 'true' if self.flush else 'false',
	'  adj-rib-out: %s;\n' % 'true' if self.adjribout else 'false',
	'  md5: %d;\n' % self.ttl if self.ttl else '',
	'  ttl-security: %d;\n' % self.ttl if self.ttl else '',
	'    asn4 enable;\n' if self.asn4 else '    asn4 disable;\n',
	'    route-refresh;\n' if self.route_refresh else '',
	'    graceful-restart %s;\n' % self.graceful_restart if self.graceful_restart else '',
	'    add-path %s;\n' % AddPath.string[self.add_path] if self.add_path else '',
	'    multi-session;\n' if self.multisession else '',
	'    operational;\n' if self.operational else '',
	'    aigp;\n' if self.aigp else '',
	families,
	api,
	changes
)

	def __str__ (self):
		return self.pprint(False)
예제 #9
0
class Neighbor(object):
    def __init__(self):
        # self.logger should not be used here as long as we do use deepcopy as it contains a Lock
        self.description = ''
        self.router_id = None
        self.local_address = None
        self.peer_address = None
        self.peer_as = None
        self.local_as = None
        self.hold_time = HoldTime(180)
        self.asn4 = None
        self.add_path = 0
        self.md5 = None
        self.ttl = None
        self.group_updates = None
        self.flush = None
        self.adjribout = None

        self.api = APIOptions()

        self.passive = False

        # capability
        self.route_refresh = False
        self.graceful_restart = False
        self.multisession = None
        self.add_path = None
        self.aigp = None

        self._families = []
        self.rib = None

        self.operational = None
        self.eor = deque()
        self.asm = dict()

        self.messages = deque()
        self.refresh = deque()

    def identificator(self):
        # It is possible to :
        # - have multiple exabgp toward one peer on the same host ( use of pid )
        # - have more than once connection toward a peer
        # - each connection has it own neihgbor (hence why identificator is not in Protocol)
        return str(self.peer_address)

    def make_rib(self):
        self.rib = RIB(self.name(), self.adjribout, self._families)

    # will resend all the routes once we reconnect
    def reset_rib(self):
        self.rib.reset()
        self.messages = deque()
        self.refresh = deque()

    # back to square one, all the routes are removed
    def clear_rib(self):
        self.rib.clear()
        self.messages = deque()
        self.refresh = deque()

    def name(self):
        if self.multisession:
            session = '/'.join("%s-%s" % (afi.name(), safi.name())
                               for (afi, safi) in self.families())
        else:
            session = 'in-open'
        return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (
            self.peer_address, self.local_address, self.local_as, self.peer_as,
            self.router_id, session)

    def families(self):
        # this list() is important .. as we use the function to modify self._families
        return list(self._families)

    def add_family(self, family):
        # the families MUST be sorted for neighbor indexing name to be predictable for API users
        if not family in self.families():
            afi, safi = family
            d = dict()
            d[afi] = [
                safi,
            ]
            for afi, safi in self._families:
                d.setdefault(afi, []).append(safi)
            self._families = [(afi, safi) for afi in sorted(d)
                              for safi in sorted(d[afi])]

    def remove_family(self, family):
        if family in self.families():
            self._families.remove(family)

    def missing(self):
        if self.local_address is None: return 'local-address'
        if self.peer_address is None: return 'peer-address'
        if self.local_as is None: return 'local-as'
        if self.peer_as is None: return 'peer-as'
        if self.peer_address.afi == AFI.ipv6 and not self.router_id:
            return 'router-id'
        return ''

    # This function only compares the neighbor BUT NOT ITS ROUTES
    def __eq__(self, other):
        return \
         self.router_id == other.router_id and \
         self.local_address == other.local_address and \
         self.local_as == other.local_as and \
         self.peer_address == other.peer_address and \
         self.peer_as == other.peer_as and \
         self.passive == other.passive and \
         self.hold_time == other.hold_time and \
         self.md5 == other.md5 and \
         self.ttl == other.ttl and \
         self.route_refresh == other.route_refresh and \
         self.graceful_restart == other.graceful_restart and \
         self.multisession == other.multisession and \
         self.add_path == other.add_path and \
         self.operational == other.operational and \
         self.group_updates == other.group_updates and \
         self.flush == other.flush and \
         self.adjribout == other.adjribout and \
         self.families() == other.families()

    def __ne__(self, other):
        return not self.__eq__(other)

    def pprint(self, with_changes=True):
        changes = ''
        if with_changes:
            changes += '\nstatic { '
            for changes in self.rib.incoming.queued_changes():
                changes += '\n    %s' % changes.extensive()
            changes += '\n}'

        families = ''
        for afi, safi in self.families():
            families += '\n    %s %s;' % (afi.name(), safi.name())

        _receive = []

        _receive.extend([
            '      parsed;\n',
        ] if self.api['receive-parsed'] else [])
        _receive.extend([
            '      packets;\n',
        ] if self.api['receive-packets'] else [])
        _receive.extend([
            '      consolidate;\n',
        ] if self.api['consolidate'] else [])

        _receive.extend([
            '      neighbor-changes;\n',
        ] if self.api['neighbor-changes'] else [])
        _receive.extend([
            '      notification;\n',
        ] if self.api[Message.ID.NOTIFICATION] else [])
        _receive.extend([
            '      open;\n',
        ] if self.api[Message.ID.OPEN] else [])
        _receive.extend([
            '      keepalive;\n',
        ] if self.api[Message.ID.KEEPALIVE] else [])
        _receive.extend([
            '      update;\n',
        ] if self.api[Message.ID.UPDATE] else [])
        _receive.extend([
            '      refresh;\n',
        ] if self.api[Message.ID.ROUTE_REFRESH] else [])
        _receive.extend([
            '      operational;\n',
        ] if self.api[Message.ID.OPERATIONAL] else [])
        _receive.extend([
            '      parsed;\n',
        ] if self.api['receive-parsed'] else [])
        _receive.extend([
            '      packets;\n',
        ] if self.api['receive-packets'] else [])
        _receive.extend([
            '      consolidate;\n',
        ] if self.api['consolidate'] else [])

        receive = ''.join(_receive)

        _send = []
        _send.extend([
            '      packets;\n',
        ] if self.api['send-packets'] else [])
        send = ''.join(_send)

        return """\
neighbor %s {
  description "%s";
  router-id %s;
  local-address %s;
  local-as %s;
  peer-as %s;%s
  hold-time %s;
%s%s%s%s%s
  capability {
%s%s%s%s%s%s%s  }
  family {%s
  }
  process {
%s%s  }%s
}""" % (self.peer_address, self.description, self.router_id,
        self.local_address, self.local_as, self.peer_as, '\n  passive;\n'
        if self.passive else '', self.hold_time, '  group-updates: %s;\n' %
        (self.group_updates if self.group_updates else ''),
        '  auto-flush: %s;\n' %
        ('true' if self.flush else 'false'), '  adj-rib-out: %s;\n' %
        ('true' if self.adjribout else 'false'), '  md5 "%s";\n' %
        self.md5 if self.md5 else '', '  ttl-security: %s;\n' %
        (self.ttl if self.ttl else ''), '    asn4 %s;\n' %
        ('enable' if self.asn4 else 'disable'), '    route-refresh %s;\n' %
        ('enable' if self.route_refresh else 'disable'),
        '    graceful-restart %s;\n' %
        (self.graceful_restart if self.graceful_restart else 'disable'),
        '    add-path %s;\n' %
        (AddPath.string[self.add_path] if self.add_path else 'disable'),
        '    multi-session %s;\n' %
        ('enable' if self.multisession else 'disable'),
        '    operational %s;\n' %
        ('enable' if self.operational else 'disable'), '    aigp %s;\n' %
        ('enable' if self.aigp else 'disable'), families,
        '    receive {\n%s    }\n' % receive if receive else '',
        '    send {\n%s    }\n' % send if send else '', changes)

    def __str__(self):
        return self.pprint(False)
예제 #10
0
파일: neighbor.py 프로젝트: aabdnn/exabgp
class Neighbor (object):
	_GLOBAL = {'uid': 1}

	def __init__ (self):
		# self.logger should not be used here as long as we do use deepcopy as it contains a Lock
		self.description = None
		self.router_id = None
		self.host_name = None
		self.domain_name = None
		self.local_address = None
		self.range_size = 1
		# local_address uses auto discovery
		self.auto_discovery = False
		self.peer_address = None
		self.peer_as = None
		self.local_as = None
		self.hold_time = None
		self.asn4 = None
		self.add_path = None
		self.md5_password = None
		self.md5_base64 = False
		self.md5_ip = None
		self.ttl_in = None
		self.ttl_out = None
		self.group_updates = None
		self.flush = None
		self.adj_rib_in = None
		self.adj_rib_out = None

		self.manual_eor = False

		self.api = None  # XXX: not scriptable - is replaced outside the class
		# passive indicate that we do not establish outgoing connections
		self.passive = False
		# the port to listen on ( zero mean that we do not listen )
		self.listen = 0
		# the port to connect to
		self.connect = 0

		# was this Neighbor generated from a range
		self.generated = False

		# capability
		self.route_refresh = False
		self.graceful_restart = False
		self.multisession = None
		self.add_path = None
		self.aigp = None

		self._families = []
		self._addpaths = []
		self.rib = None

		# The routes we have parsed from the configuration
		self.changes = []
		# On signal update, the previous routes so we can compare what changed
		self.backup_changes = []

		self.operational = None
		self.eor = deque()
		self.asm = dict()

		self.messages = deque()
		self.refresh = deque()

		self.counter = Counter()
		# It is possible to :
		# - have multiple exabgp toward one peer on the same host ( use of pid )
		# - have more than once connection toward a peer
		# - each connection has it own neihgbor (hence why identificator is not in Protocol)
		self.uid = '%d' % self._GLOBAL['uid']
		self._GLOBAL['uid'] += 1

	def id (self):
		return 'neighbor-%s' % self.uid

	def make_rib (self):
		self.rib = RIB(self.name(),self.adj_rib_in,self.adj_rib_out,self._families)

	# will resend all the routes once we reconnect
	def reset_rib (self):
		self.rib.reset()
		self.messages = deque()
		self.refresh = deque()

	# back to square one, all the routes are removed
	def clear_rib (self):
		self.rib.clear()
		self.messages = deque()
		self.refresh = deque()

	def name (self):
		if self.multisession:
			session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
		else:
			session = 'in-open'
		return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (
			self.peer_address,
			self.local_address if self.peer_address is not None else 'auto',
			self.local_as if self.local_as is not None else 'auto',
			self.peer_as if self.peer_as is not None else 'auto',
			self.router_id,
			session
		)

	def families (self):
		# this list() is important .. as we use the function to modify self._families
		return list(self._families)

	def addpaths (self):
		# this list() is important .. as we use the function to modify self._families
		return list(self._addpaths)

	def add_family (self, family):
		# the families MUST be sorted for neighbor indexing name to be predictable for API users
		# this list() is important .. as we use the function to modify self._families
		if family not in self.families():
			afi,safi = family
			d = dict()
			d[afi] = [safi,]
			for afi,safi in self._families:
				d.setdefault(afi,[]).append(safi)
			self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

	def add_addpath (self, family):
		# the families MUST be sorted for neighbor indexing name to be predictable for API users
		# this list() is important .. as we use the function to modify self._families
		if family not in self.addpaths():
			afi,safi = family
			d = dict()
			d[afi] = [safi,]
			for afi,safi in self._addpaths:
				d.setdefault(afi,[]).append(safi)
			self._addpaths = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]

	def remove_family (self, family):
		if family in self.families():
			self._families.remove(family)

	def remove_addpath (self, family):
		if family in self.addpaths():
			self._addpaths.remove(family)

	def missing (self):
		if self.local_address is None and not self.auto_discovery:
			return 'local-address'
		if self.listen > 0 and self.auto_discovery:
			return 'local-address'
		if self.peer_address is None:
			return 'peer-address'
		if self.auto_discovery and not self.router_id:
			return 'router-id'
		if self.peer_address.afi == AFI.ipv6 and not self.router_id:
			return 'router-id'
		return ''

	# This function only compares the neighbor BUT NOT ITS ROUTES
	def __eq__ (self, other):
		# Comparing local_address is skipped in the case where either
		# peer is configured to auto discover its local address. In
		# this case it can happen that one local_address is None and
		# the other one will be set to the auto disocvered IP address.
		auto_discovery = self.auto_discovery or other.auto_discovery
		return \
			self.router_id == other.router_id and \
			(auto_discovery or self.local_address == other.local_address) and \
			self.auto_discovery == other.auto_discovery and \
			self.local_as == other.local_as and \
			self.peer_address == other.peer_address and \
			self.peer_as == other.peer_as and \
			self.passive == other.passive and \
			self.listen == other.listen and \
			self.connect == other.connect and \
			self.hold_time == other.hold_time and \
			self.host_name == other.host_name and \
			self.domain_name == other.domain_name and \
			self.md5_password == other.md5_password and \
			self.md5_ip == other.md5_ip and \
			self.ttl_in == other.ttl_in and \
			self.ttl_out == other.ttl_out and \
			self.route_refresh == other.route_refresh and \
			self.graceful_restart == other.graceful_restart and \
			self.multisession == other.multisession and \
			self.add_path == other.add_path and \
			self.operational == other.operational and \
			self.group_updates == other.group_updates and \
			self.flush == other.flush and \
			self.adj_rib_in == other.adj_rib_in and \
			self.adj_rib_out == other.adj_rib_out and \
			self.families() == other.families()

	def __ne__ (self, other):
		return not self.__eq__(other)

	def string (self, with_changes=True):
		changes = ''
		if with_changes:
			changes += '\nstatic { '
			for changes in self.rib.incoming.queued_changes():
				changes += '\n\t\t%s' % changes.extensive()
			changes += '\n}'

		families = ''
		for afi,safi in self.families():
			families += '\n\t\t%s %s;' % (afi.name(),safi.name())

		addpaths = ''
		for afi,safi in self.addpaths():
			addpaths += '\n\t\t%s %s;' % (afi.name(),safi.name())

		codes = Message.CODE

		_extension_global = {
			'neighbor-changes': 'neighbor-changes',
			'negotiated':       'negotiated',
			'fsm':              'fsm',
			'signal':           'signal',
		}

		_extension_receive = {
			'receive-packets':                        'packets',
			'receive-parsed':                         'parsed',
			'receive-consolidate':                    'consolidate',
			'receive-%s' % codes.NOTIFICATION.SHORT:  'notification',
			'receive-%s' % codes.OPEN.SHORT:          'open',
			'receive-%s' % codes.KEEPALIVE.SHORT:     'keepalive',
			'receive-%s' % codes.UPDATE.SHORT:        'update',
			'receive-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh',
			'receive-%s' % codes.OPERATIONAL.SHORT:   'operational',
		}

		_extension_send = {
			'send-packets':                        'packets',
			'send-parsed':                         'parsed',
			'send-consolidate':                    'consolidate',
			'send-%s' % codes.NOTIFICATION.SHORT:  'notification',
			'send-%s' % codes.OPEN.SHORT:          'open',
			'send-%s' % codes.KEEPALIVE.SHORT:     'keepalive',
			'send-%s' % codes.UPDATE.SHORT:        'update',
			'send-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh',
			'send-%s' % codes.OPERATIONAL.SHORT:   'operational',
		}

		apis = ''

		for process in self.api.get('processes',[]):
			_global = []
			_receive = []
			_send = []

			for api,name in _extension_global.items():
				_global.extend(['\t\t%s;\n' % name,] if process in self.api[api] else [])

			for api,name in _extension_receive.items():
				_receive.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else [])

			for api,name in _extension_send.items():
				_send.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else [])

			_api  = '\tapi {\n'
			_api += '\t\tprocesses [ %s ];\n' % process
			_api += ''.join(_global)
			if _receive:
				_api += '\t\treceive {\n'
				_api += ''.join(_receive)
				_api += '\t\t}\n'
			if _send:
				_api += '\t\tsend {\n'
				_api += ''.join(_send)
				_api += '\t\t}\n'
			_api += '\t}\n'

			apis += _api

		returned = \
			'neighbor %s {\n' \
			'\tdescription "%s";\n' \
			'\trouter-id %s;\n' \
			'\thost-name %s;\n' \
			'\tdomain-name %s;\n' \
			'\tlocal-address %s;\n' \
			'\tlocal-as %s;\n' \
			'\tpeer-as %s;\n' \
			'\thold-time %s;\n' \
			'\tmanual-eor %s;\n' \
			'%s%s%s%s%s%s%s%s%s%s%s\n' \
			'\tcapability {\n' \
			'%s%s%s%s%s%s%s%s\t}\n' \
			'\tfamily {%s\n' \
			'\t}\n' \
			'\tadd-path {%s\n' \
			'\t}\n' \
			'%s' \
			'%s' \
			'}' % (
				self.peer_address,
				self.description,
				self.router_id,
				self.host_name,
				self.domain_name,
				self.local_address if not self.auto_discovery else 'auto',
				self.local_as,
				self.peer_as,
				self.hold_time,
				'true' if self.manual_eor else 'false',
				'\n\tpassive %s;\n' % ('true' if self.passive else 'false'),
				'\n\tlisten %d;\n' % self.listen if self.listen else '',
				'\n\tconnect %d;\n' % self.connect if self.connect else '',
				'\tgroup-updates %s;\n' % ('true' if self.group_updates else 'false'),
				'\tauto-flush %s;\n' % ('true' if self.flush else 'false'),
				'\tadj-rib-in %s;\n' % ('true' if self.adj_rib_in else 'false'),
				'\tadj-rib-out %s;\n' % ('true' if self.adj_rib_out else 'false'),
				'\tmd5-password "%s";\n' % self.md5_password if self.md5_password else '',
				'\tmd5-base64 %s;\n' % ('true' if self.md5_base64 is True else 'false' if self.md5_base64 is False else 'auto'),
				'\tmd5-ip "%s";\n' % self.md5_ip if not self.auto_discovery else '',
				'\toutgoing-ttl %s;\n' % self.ttl_out if self.ttl_out else '',
				'\tincoming-ttl %s;\n' % self.ttl_in if self.ttl_in else '',
				'\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'),
				'\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'),
				'\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'),
				'\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'),
				'\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'),
				'\t\toperational %s;\n' % ('enable' if self.operational else 'disable'),
				'\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'),
				families,
				addpaths,
				apis,
				changes
			)

		# '\t\treceive {\n%s\t\t}\n' % receive if receive else '',
		# '\t\tsend {\n%s\t\t}\n' % send if send else '',
		return returned.replace('\t','  ')

	def __str__ (self):
		return self.string(False)