def redirect (tokeniser): data = tokeniser() count = data.count(':') if count == 0: return IP.create(data), ExtendedCommunities().add(TrafficNextHopSimpson(False)) if count == 1: prefix,suffix = data.split(':',1) if prefix.count('.'): raise ValueError('this format has been deprecated as it does not make sense and it is not supported by other vendors') asn = int(prefix) route_target = int(suffix) if asn >= pow(2, 32): raise ValueError('asn is a 32 bits number, value too large %s' % asn) if asn >= pow(2,16): if route_target >= pow(2, 16): raise ValueError('asn is a 32 bits number, route target can only be 16 bit %s' % route_target) return NoNextHop, ExtendedCommunities().add(TrafficRedirectASN4(asn, route_target)) if route_target >= pow(2,32): raise ValueError('route target is a 32 bits number, value too large %s' % route_target) return NoNextHop,ExtendedCommunities().add(TrafficRedirect(asn,route_target)) else: elements = data.split(':') ip = ':'.join(elements[:-1]) asn = int(elements[-1]) return IP.create(ip), ExtendedCommunities().add(TrafficRedirectIPv6(ip,asn))
def test99_EVPNMACCreatePackUnpack(self): '''Test pack/unpack for E-VPN MAC routes''' nlri = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1")) packed = nlri.pack() unpacked,leftover = EVPN.unpack_nlri(AFI(AFI.l2vpn), SAFI(SAFI.evpn), packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC7432 self.assertTrue(isinstance(unpacked, EVPNMAC)) self.assertEqual("42.42.42.42:5", unpacked.rd._str()) self.assertEqual(ESI.DEFAULT, unpacked.esi.esi) self.assertEqual(EthernetTag(111), unpacked.etag) self.assertEqual(MAC("01:02:03:04:05:06"), unpacked.mac) self.assertEqual(IP.create("1.1.1.1"), unpacked.ip) self.assertEqual(1, len(unpacked.label.labels)) self.assertEqual(42, unpacked.label.labels[0])
def listen_on(self, local_addr, remote_addr, port, md5_password, md5_base64, ttl_in): try: if not remote_addr: remote_addr = IP.create( '0.0.0.0') if local_addr.ipv4() else IP.create('::') self._listen(local_addr, remote_addr, port, md5_password, md5_base64, ttl_in) self.logger.debug( 'listening for BGP session(s) on %s:%d%s' % (local_addr, port, ' with MD5' if md5_password else ''), 'network') return True except NetworkError as exc: if os.geteuid() != 0 and port <= 1024: self.logger.critical( 'can not bind to %s:%d, you may need to run ExaBGP as root' % (local_addr, port), 'network') else: self.logger.critical( 'can not bind to %s:%d (%s)' % (local_addr, port, str(exc)), 'network') self.logger.critical( 'unset exabgp.tcp.bind if you do not want listen for incoming connections', 'network') self.logger.critical( 'and check that no other daemon is already binding to port %d' % port, 'network') return False
def test99_EVPNPrefixCreatePackUnpack(self): '''Test pack/unpack for E-VPN Prefix routes''' nlri = EVPNPrefix(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), Labels([42], True), IP.create("1.1.1.0"),24, IP.create("2.2.2.2"), ) packed = nlri.pack() unpacked,leftover = EVPN.unpack_nlri(AFI.l2vpn, SAFI.evpn, packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC7432 self.assertTrue(isinstance(unpacked, EVPNPrefix)) self.assertEqual("42.42.42.42:5", unpacked.rd._str()) self.assertEqual(ESI.DEFAULT, unpacked.esi.esi) self.assertEqual(EthernetTag(111), unpacked.etag) self.assertEqual(IP.create("1.1.1.0"), unpacked.ip) self.assertEqual(24, unpacked.iplen) self.assertEqual(IP.create("2.2.2.2"), unpacked.gwip) self.assertEqual(1, len(unpacked.label.labels)) self.assertEqual(42, unpacked.label.labels[0])
def test100_EVPNMACHashEqual(self): ''' Two indistinct EVPN NLRI should hash to the same value, and be equal ''' nlri1 = EVPNMAC( RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), ) nlri2 = EVPNMAC( RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), ) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertEqual(nlri1, nlri2)
def test99_EVPNMACCreatePackUnpack(self): '''Test pack/unpack for E-VPN MAC routes''' nlri = EVPNMAC( RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), ) packed = nlri.pack() unpacked, leftover = EVPN.unpack_nlri(AFI.l2vpn, SAFI.evpn, packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC7432 self.assertTrue(isinstance(unpacked, EVPNMAC)) self.assertEqual("42.42.42.42:5", unpacked.rd._str()) self.assertEqual(ESI.DEFAULT, unpacked.esi.esi) self.assertEqual(EthernetTag(111), unpacked.etag) self.assertEqual(MAC("01:02:03:04:05:06"), unpacked.mac) self.assertEqual(IP.create("1.1.1.1"), unpacked.ip) self.assertEqual(1, len(unpacked.label.labels)) self.assertEqual(42, unpacked.label.labels[0])
def redirect(tokeniser): data = tokeniser() count = data.count(':') if count == 0: return IP.create(data), ExtendedCommunities().add( TrafficNextHopSimpson(False)) if count == 1: prefix, suffix = data.split(':', 1) if prefix.count('.'): raise ValueError( 'this format has been deprecated as it does not make sense and it is not supported by other vendors' ) asn = int(prefix) route_target = int(suffix) if asn >= pow(2, 32): raise ValueError('asn is a 32 bits number, value too large %s' % asn) if asn >= pow(2, 16): if route_target >= pow(2, 16): raise ValueError( 'asn is a 32 bits number, route target can only be 16 bit %s' % route_target) return NoNextHop, ExtendedCommunities().add( TrafficRedirectASN4(asn, route_target)) if route_target >= pow(2, 32): raise ValueError( 'route target is a 32 bits number, value too large %s' % route_target) return NoNextHop, ExtendedCommunities().add( TrafficRedirect(asn, route_target)) else: explicit_v6 = ']:' in data # ipv4 if not explicit_v6 and data.count(':') == 1: return IP.create(data), ExtendedCommunities().add( TrafficNextHopSimpson(False)) # ipv6 using []: notation if explicit_v6: ip, asn = data.split(']:') ip = ip.replace('[', '', 1) # FIXME: should this be 2^16 ?? if asn >= pow(2, 32): raise ValueError( 'asn is a 32 bits number, value too large %s' % asn) return IP.create(ip), ExtendedCommunities().add( TrafficRedirectIPv6(ip, asn)) raise ValueError( 'it looks like you tried to use an IPv6 but did not enclose it in []' )
def listen_on (self, local_addr, remote_addr, port, md5_password, md5_base64, ttl_in): try: if not remote_addr: remote_addr = IP.create('0.0.0.0') if local_addr.ipv4() else IP.create('::') self._listen(local_addr, remote_addr, port, md5_password, md5_base64, ttl_in) self.logger.debug('listening for BGP session(s) on %s:%d%s' % (local_addr, port,' with MD5' if md5_password else ''),'network') return True except NetworkError as exc: if os.geteuid() != 0 and port <= 1024: self.logger.critical('can not bind to %s:%d, you may need to run ExaBGP as root' % (local_addr, port),'network') else: self.logger.critical('can not bind to %s:%d (%s)' % (local_addr, port,str(exc)),'network') self.logger.critical('unset exabgp.tcp.bind if you do not want listen for incoming connections','network') self.logger.critical('and check that no other daemon is already binding to port %d' % port,'network') return False
def connect (self): # allows to test the protocol code using modified StringIO with a extra 'pending' function if not self.connection: local = self.neighbor.md5_ip.top() if not self.neighbor.auto_discovery else None peer = self.neighbor.peer_address.top() afi = self.neighbor.peer_address.afi md5 = self.neighbor.md5_password md5_base64 = self.neighbor.md5_base64 ttl_out = self.neighbor.ttl_out self.connection = Outgoing(afi,peer,local,self.port,md5,md5_base64,ttl_out) if not local and self.connection.init: self.neighbor.local_address = IP.create(self.connection.local) if self.neighbor.router_id is None and self.neighbor.local_address.afi == AFI.ipv4: self.neighbor.router_id = self.neighbor.local_address try: generator = self.connection.establish() while True: connected = six.next(generator) if not connected: yield False continue if self.peer.neighbor.api['neighbor-changes']: self.peer.reactor.processes.connected(self.peer.neighbor) yield True return except StopIteration: # close called by the caller # self.close('could not connect to remote end') yield False return
def connect(self): # allows to test the protocol code using modified StringIO with a extra 'pending' function if not self.connection: local = self.neighbor.md5_ip.top( ) if not self.neighbor.auto_discovery else None peer = self.neighbor.peer_address.top() afi = self.neighbor.peer_address.afi md5 = self.neighbor.md5_password md5_base64 = self.neighbor.md5_base64 ttl_out = self.neighbor.ttl_out self.connection = Outgoing(afi, peer, local, self.port, md5, md5_base64, ttl_out) if not self.connection.init: yield False return if not local: self.neighbor.local_address = IP.create(self.connection.local) if self.neighbor.router_id is None and self.neighbor.local_address.afi == AFI.ipv4: self.neighbor.router_id = self.neighbor.local_address for connected in self.connection.establish(): if not connected: yield False continue if self.peer.neighbor.api['neighbor-changes']: self.peer.reactor.processes.connected(self.peer.neighbor) yield True return
def _multi_neighbor (self, scope, name, command, tokens): if len(tokens) != 1: return self.error.set('syntax: neighbor <ip> { <options> }') address = tokens[0] scope.append({}) try: scope[-1]['peer-address'] = IP.create(address) except (IndexError,ValueError,socket.error): return self.error.set('"%s" is not a valid IP address' % address) while True: r = self._dispatch( scope,name,'neighbor', [ 'static','flow','l2vpn', 'process','family','capability','operational' ], self._command['neighbor'] ) # XXX: THIS SHOULD ALLOW CAPABILITY AND NOT THE INDIVIDUAL SUB KEYS if r is False: return False if r is None: return True
def redirect (self, scope, name, command, tokens): try: if tokens[0].count(':') == 1: prefix,suffix = tokens[0].split(':',1) if prefix.count('.'): raise ValueError('this format has been deprecaded as it does not make sense and it is not supported by other vendors') else: asn = int(prefix) route_target = int(suffix) if asn >= pow(2,16): raise ValueError('asn is a 32 bits number, it can only be 16 bit %s' % route_target) if route_target >= pow(2,32): raise ValueError('route target is a 32 bits number, value too large %s' % route_target) scope[-1]['announce'][-1].attributes[Attribute.CODE.EXTENDED_COMMUNITY].add(TrafficRedirect(asn,route_target)) return True else: change = scope[-1]['announce'][-1] if change.nlri.nexthop is not NoNextHop: return self.error.set(self.syntax) nh = IP.create(tokens.pop(0)) change.nlri.nexthop = nh change.attributes[Attribute.CODE.EXTENDED_COMMUNITY].add(TrafficNextHop(False)) return True except (IndexError,ValueError): return self.error.set(self.syntax)
def connect (self): # allows to test the protocol code using modified StringIO with a extra 'pending' function if not self.connection: local = self.neighbor.md5_ip.top() if not self.neighbor.auto_discovery else None peer = self.neighbor.peer_address.top() afi = self.neighbor.peer_address.afi md5 = self.neighbor.md5_password md5_base64 = self.neighbor.md5_base64 ttl_out = self.neighbor.ttl_out self.connection = Outgoing(afi,peer,local,self.port,md5,md5_base64,ttl_out) if not self.connection.init: yield False return if not local: self.neighbor.local_address = IP.create(self.connection.local) if self.neighbor.router_id is None and self.neighbor.local_address.afi == AFI.ipv4: self.neighbor.router_id = self.neighbor.local_address for connected in self.connection.establish(): if not connected: yield False continue if self.peer.neighbor.api['neighbor-changes']: self.peer.reactor.processes.connected(self.peer.neighbor) yield True return
def next_hop (self, scope, name, command, tokens): if scope[-1]['announce'][-1].attributes.has(Attribute.CODE.NEXT_HOP): return self.error.set(self.syntax) try: # next-hop self is unsupported ip = tokens.pop(0) if ip.lower() == 'self': if 'local-address' in scope[-1]: la = scope[-1]['local-address'] elif self._nexthopself: la = self._nexthopself else: return self.error.set('next-hop self can only be specified with a neighbor') nh = IP.unpack(la.pack()) else: nh = IP.create(ip) change = scope[-1]['announce'][-1] nlri = change.nlri afi = nlri.afi safi = nlri.safi nlri.nexthop = nh if afi == AFI.ipv4 and safi in (SAFI.unicast,SAFI.multicast): change.attributes.add(Attribute.unpack(NextHop.ID,NextHop.FLAG,nh.packed,None)) # NextHop(nh.ip,nh.packed) does not cache the result, using unpack does # change.attributes.add(NextHop(nh.ip,nh.packed)) return True except Exception: return self.error.set(self.syntax)
def connect(self): # allows to test the protocol code using modified StringIO with a extra 'pending' function if self.connection: return local = self.neighbor['md5-ip'].top( ) if not self.neighbor.auto_discovery else None peer = self.neighbor['peer-address'].top() afi = self.neighbor['peer-address'].afi md5 = self.neighbor['md5-password'] md5_base64 = self.neighbor['md5-base64'] ttl_out = self.neighbor['outgoing-ttl'] self.connection = Outgoing(afi, peer, local, self.port, md5, md5_base64, ttl_out) for connected in self.connection.establish(): yield False if self.peer.neighbor.api['neighbor-changes']: self.peer.reactor.processes.connected(self.peer.neighbor) if not local: self.neighbor['local-address'] = IP.create(self.connection.local) if self.neighbor['router-id'] is None and self.neighbor[ 'local-address'].afi == AFI.ipv4: self.neighbor['router-id'] = self.neighbor['local-address'] yield True
def connect(self): # allows to test the protocol code using modified StringIO with a extra 'pending' function if not self.connection: local = self.neighbor.md5_ip.top( ) if not self.neighbor.auto_discovery else None peer = self.neighbor.peer_address.top() afi = self.neighbor.peer_address.afi md5 = self.neighbor.md5_password md5_base64 = self.neighbor.md5_base64 ttl_out = self.neighbor.ttl_out self.connection = Outgoing(afi, peer, local, self.port, md5, md5_base64, ttl_out) if not local and self.connection.init: self.neighbor.local_address = IP.create(self.connection.local) if self.neighbor.router_id is None and self.neighbor.local_address.afi == AFI.ipv4: self.neighbor.router_id = self.neighbor.local_address try: generator = self.connection.establish() while True: connected = six.next(generator) if not connected: yield False continue if self.peer.neighbor.api['neighbor-changes']: self.peer.reactor.processes.connected( self.peer.neighbor) yield True return except StopIteration: # close called by the caller # self.close('could not connect to remote end') yield False return
def _multi_neighbor (self, scope, tokens): if len(tokens) != 1: return self.error.set('syntax: neighbor <ip> { <options> }') address = tokens[0] scope.append({}) try: scope[-1]['peer-address'] = IP.create(address) except (IndexError,ValueError,socket.error): return self.error.set('"%s" is not a valid IP address' % address) while True: r = self._dispatch( scope,'neighbor', [ 'static','flow','l2vpn', 'process','family','capability','operational' ], [ 'description','router-id','local-address','local-as','peer-as', 'host-name','domain-name', 'passive','listen','hold-time','add-path','graceful-restart','md5', 'ttl-security','multi-session','group-updates','asn4','aigp', 'auto-flush','adj-rib-out' ] ) # XXX: THIS SHOULD ALLOW CAPABILITY AND NOT THE INDIVIDUAL SUB KEYS if r is False: return False if r is None: return True
def next_hop(tokeniser): value = tokeniser() if value.lower() == 'self': return IPSelf(tokeniser.afi), NextHopSelf(tokeniser.afi) else: ip = IP.create(value) return ip, NextHop(ip.top())
def ip (self, scope, command, tokens): try: ip = IP.create(tokens[0]) except (IndexError,ValueError): return self.error.set('"%s" is an invalid IP address' % ' '.join(tokens)) scope[-1][command] = ip return True
def next_hop(tokeniser): value = tokeniser() if value.lower() == 'self': return NextHopSelf(AFI.ipv4) else: ip = IP.create(value) return NextHop(ip.top(), ip.pack())
def next_hop (tokeniser): value = tokeniser() if value.lower() == 'self': return NextHopSelf(AFI.ipv4) else: ip = IP.create(value) return NextHop(ip.string,ip.pack())
def new (cls, afi, safi, packed, mask, labels, rd, nexthop=None, action=OUT.UNSET): instance = cls(afi,safi,action) instance.cidr = CIDR(packed, mask) instance.labels = labels instance.rd = rd instance.nexthop = IP.create(nexthop) if nexthop else NoNextHop instance.action = action return instance
def ip(tokeniser): if not tokeniser.tokens: raise ValueError('an ip address is required') value = tokeniser() try: return IP.create(value) except (IndexError, ValueError, socket.error): raise ValueError('"%s" is an invalid IP address' % value)
def ip(self, scope, name, command, tokens): try: ip = IP.create(tokens[0]) except (IndexError, ValueError): return self.error.set('"%s" is an invalid IP address' % ' '.join(tokens)) scope[-1][command] = ip return True
def ip(tokeniser): if not tokeniser.tokens: raise ValueError("an ip address is required") value = tokeniser() try: return IP.create(value) except (IndexError, ValueError, socket.error): raise ValueError('"%s" is an invalid IP address' % value)
def next_hop (tokeniser): value = tokeniser() if value.lower() == 'self': return IPSelf(tokeniser.afi),NextHopSelf(tokeniser.afi) else: ip = IP.create(value) if ip.afi == AFI.ipv4: return ip,NextHop(ip.top()) return ip,None
def ip_list (_): ips = [] for ip in _.split(' '): if not ip: continue elif isip(ip): ips.append(IP.create(ip)) else: raise TypeError('ip %s is invalid' % ip) return ips
def ip_list(_): ips = [] for ip in _.split(' '): if not ip: continue elif isip(ip): ips.append(IP.create(ip)) else: raise TypeError('ip %s is invalid' % ip) return ips
def next_hop(tokeniser): value = tokeniser() if value.lower() == 'self': return IPSelf(AFI.undefined), NextHopSelf(AFI.undefined) else: ip = IP.create(value) if ip.afi == AFI.ipv4: return ip, NextHop(ip.top()) return ip, None
def local_address(tokeniser): if not tokeniser.tokens: raise ValueError("an ip address or 'auto' is required") value = tokeniser() if value == 'auto': return value try: return IP.create(value) except (IndexError, ValueError, socket.error): raise ValueError('"%s" is an invalid IP address' % value)
def local_address(tokeniser): if not tokeniser.tokens: raise ValueError("an ip address or 'auto' is required") value = tokeniser() if value == 'auto': return None try: return IP.create(value) except (IndexError,ValueError,socket.error): raise ValueError('"%s" is an invalid IP address' % value)
def next_hop (self, scope, name, command, tokens): try: change = scope[-1]['announce'][-1] if change.nlri.nexthop is not NoNextHop: return self.error.set(self.syntax) change.nlri.nexthop = IP.create(tokens.pop(0)) return True except (IndexError,ValueError): return self.error.set(self.syntax)
def next_hop(self, scope, name, command, tokens): try: change = scope[-1]['announce'][-1] if change.nlri.nexthop is not NoNextHop: return self.error.set(self.syntax) change.nlri.nexthop = IP.create(tokens.pop(0)) return True except (IndexError, ValueError): return self.error.set(self.syntax)
def test99_EVPNMulticastCreatePackUnpack(self): '''Test pack/unpack for E-VPN Multicast routes''' nlri = EVPNMulticast(RouteDistinguisher.fromElements("42.42.42.42", 5), EthernetTag(111), IP.create("1.1.1.1")) packed = nlri.pack() unpacked, leftover = EVPN.unpack_nlri(AFI.l2vpn, SAFI.evpn, packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC7432 self.assertTrue(isinstance(unpacked, EVPNMulticast)) self.assertEqual("42.42.42.42:5", unpacked.rd._str()) self.assertEqual(EthernetTag(111), unpacked.etag) self.assertEqual(IP.create("1.1.1.1"), unpacked.ip)
def copy (self, scope, name, command, tokens): # README: We are setting the ASN as zero as that what Juniper (and Arbor) did when we created a local flow route try: if scope[-1]['announce'][-1].attributes.has(Attribute.CODE.NEXT_HOP): return self.error.set(self.syntax) change = scope[-1]['announce'][-1] change.nlri.nexthop = IP.create(tokens.pop(0)) change.attributes[Attribute.CODE.EXTENDED_COMMUNITY].add(TrafficNextHop(True)) return True except (IndexError,ValueError): return self.error.set(self.syntax)
def test100_EVPNMACHashEqual(self): ''' Two indistinct EVPN NLRI should hash to the same value, and be equal ''' nlri1 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1")) nlri2 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1")) self.assertEqual(hash(nlri1), hash(nlri2)) self.assertEqual(nlri1, nlri2)
def test99_EVPNMulticastCreatePackUnpack(self): '''Test pack/unpack for E-VPN Multicast routes''' nlri = EVPNMulticast(RouteDistinguisher.fromElements("42.42.42.42", 5), EthernetTag(111), IP.create("1.1.1.1")) packed = nlri.pack() unpacked,leftover = EVPN.unpack_nlri(AFI(AFI.l2vpn), SAFI(SAFI.evpn), packed, OUT.UNSET, None) self.assertEqual(0, len(leftover)) # TODO: compare packed with a reference encoding verified # as conformant with RFC7432 self.assertTrue(isinstance(unpacked, EVPNMulticast)) self.assertEqual("42.42.42.42:5", unpacked.rd._str()) self.assertEqual(EthernetTag(111), unpacked.etag) self.assertEqual(IP.create("1.1.1.1"), unpacked.ip)
def test101_EVPNHashEqual_somefieldsvary(self): ''' Two EVPN MAC NLRIs differing by their ESI or label or RD, or nexthop, but otherwise identical should hash to the same value, and be equal ''' nlri0 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1")) # Esi nlri1 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(['1' for _ in range(0, 10)]), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1")) # label nlri2 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([4444], True), IP.create("1.1.1.1")) # IP: different IPs, but same MACs: different route nlri3 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("2.2.2.2")) # with a next hop... nlri4 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), IP.pton("10.10.10.10")) nlri5 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(), EthernetTag(111), MAC("01:02:03:04:05:06"), 6 * 8, Labels([42], True), IP.create("1.1.1.1"), IP.pton("11.11.11.11")) self.assertEqual(hash(nlri0), hash(nlri1)) self.assertEqual(hash(nlri0), hash(nlri2)) self.assertEqual(hash(nlri0), hash(nlri4)) self.assertEqual(nlri0, nlri1) self.assertEqual(nlri0, nlri2) self.assertEqual(nlri0, nlri4) self.assertEqual(nlri1, nlri2) self.assertEqual(nlri1, nlri4) self.assertEqual(nlri2, nlri4) self.assertEqual(nlri4, nlri5) self.assertNotEqual(hash(nlri0), hash(nlri3)) self.assertNotEqual(nlri0, nlri3) self.assertNotEqual(nlri1, nlri3) self.assertNotEqual(nlri2, nlri3) self.assertNotEqual(nlri3, nlri4)
def copy(self, scope, name, command, tokens): # README: We are setting the ASN as zero as that what Juniper (and Arbor) did when we created a local flow route try: if scope[-1]['announce'][-1].attributes.has( Attribute.CODE.NEXT_HOP): return self.error.set(self.syntax) change = scope[-1]['announce'][-1] change.nlri.nexthop = IP.create(tokens.pop(0)) change.attributes[Attribute.CODE.EXTENDED_COMMUNITY].add( TrafficNextHop(True)) return True except (IndexError, ValueError): return self.error.set(self.syntax)
def redirect (tokeniser): data = tokeniser() if data.count(':') == 1: prefix,suffix = data.split(':',1) if prefix.count('.'): raise ValueError('this format has been deprecaded as it does not make sense and it is not supported by other vendors') asn = int(prefix) route_target = int(suffix) if asn >= pow(2,16): raise ValueError('asn is a 32 bits number, it can only be 16 bit %s' % route_target) if route_target >= pow(2,32): raise ValueError('route target is a 32 bits number, value too large %s' % route_target) return NoNextHop,ExtendedCommunities().add(TrafficRedirect(asn,route_target)) else: return IP.create(data),ExtendedCommunities().add(TrafficNextHop(False))
def redirect (tokeniser): data = tokeniser() if data.count(':') == 1: prefix,suffix = data.split(':',1) if prefix.count('.'): raise ValueError('this format has been deprecaded as it does not make sense and it is not supported by other vendors') asn = int(prefix) route_target = int(suffix) if asn >= pow(2,16): raise ValueError('asn is a 32 bits number, it can only be 16 bit %s' % route_target) if route_target >= pow(2,32): raise ValueError('route target is a 32 bits number, value too large %s' % route_target) return None,ExtendedCommunities().add(TrafficRedirect(asn,route_target)) else: return IP.create(data),ExtendedCommunities().add(TrafficNextHop(False))
def redirect(self, scope, name, command, tokens): try: if tokens[0].count(':') == 1: prefix, suffix = tokens[0].split(':', 1) if prefix.count('.'): raise ValueError( 'this format has been deprecaded as it does not make sense and it is not supported by other vendors' ) else: asn = int(prefix) route_target = int(suffix) if asn >= pow(2, 16): raise ValueError( 'asn is a 32 bits number, it can only be 16 bit %s' % route_target) if route_target >= pow(2, 32): raise ValueError( 'route target is a 32 bits number, value too large %s' % route_target) scope[-1]['announce'][-1].attributes[ Attribute.CODE.EXTENDED_COMMUNITY].add( TrafficRedirect(asn, route_target)) return True else: change = scope[-1]['announce'][-1] if change.nlri.nexthop is not NoNextHop: return self.error.set(self.syntax) nh = IP.create(tokens.pop(0)) change.nlri.nexthop = nh change.attributes[Attribute.CODE.EXTENDED_COMMUNITY].add( TrafficNextHop(False)) return True except (IndexError, ValueError): return self.error.set(self.syntax)
def next_hop(self, scope, name, command, tokens): if scope[-1]['announce'][-1].attributes.has(Attribute.CODE.NEXT_HOP): return self.error.set(self.syntax) try: # next-hop self is unsupported ip = tokens.pop(0) if ip.lower() == 'self': if 'local-address' in scope[-1]: la = scope[-1]['local-address'] elif self._nexthopself: la = self._nexthopself else: return self.error.set( 'next-hop self can only be specified with a neighbor') nh = IP.unpack(la.pack()) else: nh = IP.create(ip) change = scope[-1]['announce'][-1] nlri = change.nlri afi = nlri.afi safi = nlri.safi nlri.nexthop = nh if afi == AFI.ipv4 and safi in (SAFI.unicast, SAFI.multicast): change.attributes.add( Attribute.unpack(NextHop.ID, NextHop.FLAG, nh.packed, None)) # NextHop(nh.ip,nh.packed) does not cache the result, using unpack does # change.attributes.add(NextHop(nh.ip,nh.packed)) return True except Exception: return self.error.set(self.syntax)
def ls_unicast_ipv4_neighbor_address (tokeniser): value = tokeniser() return IP.create(value)
def test101_EVPNHashEqual_somefieldsvary(self): ''' Two EVPN MAC NLRIs differing by their ESI or label or RD, or nexthop, but otherwise identical should hash to the same value, and be equal ''' nlri0 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1")) # Esi nlri1 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(1), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1")) # label nlri2 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([4444], True), IP.create("1.1.1.1")) # IP: different IPs, but same MACs: different route nlri3 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("2.2.2.2")) # with a next hop... nlri4 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1"), IP.pton("10.10.10.10")) nlri5 = EVPNMAC(RouteDistinguisher.fromElements("42.42.42.42", 5), ESI(0), EthernetTag(111), MAC("01:02:03:04:05:06"), 6*8, Labels([42], True), IP.create("1.1.1.1"), IP.pton("11.11.11.11")) self.assertEqual(hash(nlri0), hash(nlri1)) self.assertEqual(hash(nlri0), hash(nlri2)) self.assertEqual(hash(nlri0), hash(nlri4)) self.assertEqual(nlri0, nlri1) self.assertEqual(nlri0, nlri2) self.assertEqual(nlri0, nlri4) self.assertEqual(nlri1, nlri2) self.assertEqual(nlri1, nlri4) self.assertEqual(nlri2, nlri4) self.assertEqual(nlri4, nlri5) self.assertNotEqual(hash(nlri0), hash(nlri3)) self.assertNotEqual(nlri0, nlri3) self.assertNotEqual(nlri1, nlri3) self.assertNotEqual(nlri2, nlri3) self.assertNotEqual(nlri3, nlri4)
def ip(tokeniser): value = tokeniser() try: return IP.create(value) except (IndexError, ValueError, SocketError): raise ValueError('"%s" is an invalid IP address' % value)
def __init__ (self, ip, packed=None): # Need to conform to from IP interface self.ip = ip self.packed = packed if packed else IP.create(ip).pack()
def next_hop(tokeniser): value = tokeniser() if value.lower() == 'self': return NextHopSelf(AFI.ipv4) return IP.create(value)
def ls_unicast_ipv4_neighbor_address(tokeniser): value = tokeniser() return IP.create(value)
def copy(tokeniser): return IP.create(tokeniser()), ExtendedCommunities().add(TrafficNextHopSimpson(True))
def ls_unicast_ipv4_interface_address (tokeniser): value = tokeniser() return IP.create(value)
def new_connections (self): if not self.serving: return yield None reactor = self._reactor ranged_neighbor = [] for connection in self._connected(): self.logger.debug('new connection received %s' % connection.name(),'network') for key in reactor.peers: peer = reactor.peers[key] neighbor = peer.neighbor connection_local = IP.create(connection.local).address() neighbor_peer_start = neighbor.peer_address.address() neighbor_peer_next = neighbor_peer_start + neighbor.range_size if not neighbor_peer_start <= connection_local < neighbor_peer_next: continue connection_peer = IP.create(connection.peer).address() neighbor_local = neighbor.local_address.address() if connection_peer != neighbor_local: if not neighbor.auto_discovery: continue # we found a range matching for this connection # but the peer may already have connected, so # we need to iterate all individual peers before # handling "range" peers if neighbor.range_size > 1: ranged_neighbor.append(peer.neighbor) continue denied = peer.handle_connection(connection) if denied: self.logger.debug('refused connection from %s due to the state machine' % connection.name(),'network') break self.logger.debug('accepted connection from %s' % connection.name(),'network') break else: # we did not break (and nothign was found/done or we have group match) matched = len(ranged_neighbor) if matched > 1: self.logger.debug('could not accept connection from %s (more than one neighbor match)' % connection.name(),'network') reactor.asynchronous.schedule(str(uuid.uuid1()), 'sending notification (6,5)', connection.notification( 6, 5, 'could not accept the connection (more than one neighbor match)')) return if not matched: self.logger.debug('no session configured for %s' % connection.name(),'network') reactor.asynchronous.schedule(str(uuid.uuid1()), 'sending notification (6,3)', connection.notification( 6, 3, 'no session configured for the peer')) return new_neighbor = copy.copy(ranged_neighbor[0]) new_neighbor.range_size = 1 new_neighbor.generated = True new_neighbor.local_address = IP.create(connection.peer) new_neighbor.peer_address = IP.create(connection.local) new_neighbor.router_id = RouterID.create(connection.local) new_peer = Peer(new_neighbor,self) denied = new_peer.handle_connection(connection) if denied: self.logger.debug('refused connection from %s due to the state machine' % connection.name(),'network') return reactor.peers[new_neighbor.name()] = new_peer return
def new_connections(self): if not self.serving: return yield None reactor = self._reactor ranged_neighbor = [] for connection in self._connected(): for key in reactor.peers: peer = reactor.peers[key] neighbor = peer.neighbor connection_local = IP.create(connection.local).address() neighbor_peer_start = neighbor.peer_address.address() neighbor_peer_next = neighbor_peer_start + neighbor.range_size if not neighbor_peer_start <= connection_local < neighbor_peer_next: continue connection_peer = IP.create(connection.peer).address() neighbor_local = neighbor.local_address.address() if connection_peer != neighbor_local: if not neighbor.auto_discovery: continue # we found a range matching for this connection # but the peer may already have connected, so # we need to iterate all individual peers before # handling "range" peers if neighbor.range_size > 1: ranged_neighbor.append(peer.neighbor) continue denied = peer.handle_connection(connection) if denied: self.logger.debug( 'refused connection from %s due to the state machine' % connection.name(), 'network') break self.logger.debug( 'accepted connection from %s' % connection.name(), 'network') break else: # we did not break (and nothign was found/done or we have group match) matched = len(ranged_neighbor) if matched > 1: self.logger.debug( 'could not accept connection from %s (more than one neighbor match)' % connection.name(), 'network') reactor. async .schedule( str(uuid.uuid1()), 'sending notification (6,5)', connection.notification( 6, 5, b'could not accept the connection (more than one neighbor match)' )) return if not matched: self.logger.debug( 'no session configured for %s' % connection.name(), 'network') reactor. async .schedule( str(uuid.uuid1()), 'sending notification (6,3)', connection.notification( 6, 3, b'no session configured for the peer')) return new_neighbor = copy.copy(ranged_neighbor[0]) new_neighbor.range_size = 1 new_neighbor.generated = True new_neighbor.local_address = IP.create(connection.peer) new_neighbor.peer_address = IP.create(connection.local) new_peer = Peer(new_neighbor, self) denied = new_peer.handle_connection(connection) if denied: self.logger.debug( 'refused connection from %s due to the state machine' % connection.name(), 'network') return reactor.peers[new_neighbor.name()] = new_peer return
def copy (tokeniser): return IP.create(tokeniser()),ExtendedCommunities().add(TrafficNextHop(True))
def __init__(self, ip, packed=None): # Need to conform to from IP interface self.ip = ip self.packed = packed if packed else IP.create(ip).pack()
def ls_unicast_remote_node (tokeniser): value = tokeniser() return IP.create(value)
def next_hop (tokeniser): value = tokeniser() if value.lower() == 'self': return NextHopSelf(AFI.ipv4) return IP.create(value)
def ip (tokeniser): value = tokeniser() try: return IP.create(value) except (IndexError,ValueError,SocketError): raise ValueError('"%s" is an invalid IP address' % value)
def redirect_next_hop_ietf(tokeniser): ip = IP.create(tokeniser()) if ip.ipv4(): return ExtendedCommunities().add(TrafficNextHopIPv4IETF(ip, False)) else: return ExtendedCommunitiesIPv6().add(TrafficNextHopIPv6IETF(ip, False))