<s> """<STR_LIT>""" <EOL> import time <EOL> import socket <EOL> from struct import unpack <EOL> from bagpipe . exabgp . rib . table import Table <EOL> from bagpipe . exabgp . rib . delta import Delta <EOL> from bagpipe . exabgp . utils import hexa <EOL> from bagpipe . exabgp . structure . address import AFI , SAFI <EOL> from bagpipe . exabgp . structure . ip import BGPPrefix , Inet , to_IP <EOL> from bagpipe . exabgp . structure . vpn import VPNLabelledPrefix <EOL> from bagpipe . exabgp . structure . evpn import EVPNNLRI <EOL> from bagpipe . exabgp . structure . rtc import RouteTargetConstraint <EOL> from bagpipe . exabgp . structure . asn import ASN , AS_TRANS <EOL> from bagpipe . exabgp . network . connection import Connection <EOL> from bagpipe . exabgp . message import Message , defix , Failure <EOL> from bagpipe . exabgp . message . nop import NOP <EOL> from bagpipe . exabgp . message . open import Open , Unknown , Parameter , Capabilities , RouterID , MultiProtocol , RouteRefresh , CiscoRouteRefresh , MultiSession , Graceful <EOL> from bagpipe . exabgp . message . update import Update <EOL> from bagpipe . exabgp . message . update . eor import EOR <EOL> from bagpipe . exabgp . message . keepalive import KeepAlive <EOL> from bagpipe . exabgp . message . notification import Notification , Notify <EOL> from bagpipe . exabgp . message . update . route import ReceivedRoute <EOL> from bagpipe . exabgp . message . update . attributes import Attributes <EOL> from bagpipe . exabgp . message . update . attribute import AttributeID <EOL> from bagpipe . exabgp . message . update . attribute . flag import Flag <EOL> from bagpipe . exabgp . message . update . attribute . origin import Origin <EOL> from bagpipe . exabgp . message . update . attribute . aspath import ASPath , AS4Path <EOL> from bagpipe . exabgp . message . update . attribute . nexthop import NextHop <EOL> from bagpipe . exabgp . message . update . attribute . med import MED <EOL> from bagpipe . exabgp . message . update . attribute . localpref import LocalPreference <EOL> from bagpipe . exabgp . message . update . attribute . communities import Community , Communities , ECommunity , ECommunities <EOL> from bagpipe . exabgp . message . update . attribute . originator_id import OriginatorId <EOL> from bagpipe . exabgp . message . update . attribute . pmsi_tunnel import PMSITunnel <EOL> from bagpipe . exabgp . processes import ProcessError <EOL> from bagpipe . exabgp . log import Logger <EOL> logger = Logger ( ) <EOL> MAX_BACKLOG = <NUM_LIT> <EOL> class Protocol ( object ) : <EOL> decode = True <EOL> strict = False <EOL> def __init__ ( self , peer , connection = None ) : <EOL> self . peer = peer <EOL> self . neighbor = peer . neighbor <EOL> self . connection = connection <EOL> self . _delta = Delta ( Table ( peer ) ) <EOL> self . _asn4 = False <EOL> self . _messages = { } <EOL> self . _frozen = <NUM_LIT:0> <EOL> self . message_size = <NUM_LIT> <EOL> def me ( self , message ) : <EOL> return "<STR_LIT>" % ( self . peer . neighbor . peer_address , self . peer . neighbor . peer_as , message ) <EOL> def connect ( self ) : <EOL> if not self . connection : <EOL> peer = self . neighbor . peer_address <EOL> local = self . neighbor . local_address <EOL> md5 = self . neighbor . md5 <EOL> ttl = self . neighbor . ttl <EOL> self . connection = Connection ( peer , local , md5 , ttl ) <EOL> message = '<STR_LIT>' % self . peer . neighbor . peer_address <EOL> try : <EOL> proc = self . peer . supervisor . processes <EOL> for name in proc . notify ( self . neighbor . peer_address ) : <EOL> proc . write ( name , message ) <EOL> except ProcessError : <EOL> raise Failure ( '<STR_LIT>' % message ) <EOL> def check_keepalive ( self ) : <EOL> left = int ( self . connection . last_read + self . neighbor . hold_time - time . time ( ) ) <EOL> if left <= <NUM_LIT:0> : <EOL> raise Notify ( <NUM_LIT:4> , <NUM_LIT:0> ) <EOL> return left <EOL> def close ( self ) : <EOL> if self . connection : <EOL> self . connection . close ( ) <EOL> self . connection = None <EOL> message = '<STR_LIT>' % self . peer . neighbor . peer_address <EOL> try : <EOL> proc = self . peer . supervisor . processes <EOL> for name in proc . notify ( self . neighbor . peer_address ) : <EOL> proc . write ( name , message ) <EOL> except ProcessError : <EOL> raise Failure ( '<STR_LIT>' % message ) <EOL> def read_message ( self ) : <EOL> if not self . connection . pending ( True ) : <EOL> return NOP ( '<STR_LIT>' ) <EOL> length = <NUM_LIT> <EOL> data = '<STR_LIT>' <EOL> while length : <EOL> if self . connection . pending ( ) : <EOL> delta = self . connection . read ( length ) <EOL> data += delta <EOL> length -= len ( delta ) <EOL> if not data : <EOL> raise Failure ( '<STR_LIT>' ) <EOL> if data [ : <NUM_LIT:16> ] != Message . MARKER : <EOL> raise Notify ( <NUM_LIT:1> , <NUM_LIT:1> , '<STR_LIT>' ) <EOL> raw_length = data [ <NUM_LIT:16> : <NUM_LIT> ] <EOL> length = unpack ( '<STR_LIT>' , raw_length ) [ <NUM_LIT:0> ] <EOL> msg = data [ <NUM_LIT> ] <EOL> if ( length < <NUM_LIT> or length > <NUM_LIT> ) : <EOL> raise Notify ( <NUM_LIT:1> , <NUM_LIT:2> ) <EOL> if ( <EOL> ( msg == Open . TYPE and length < <NUM_LIT> ) or <EOL> ( msg == Update . TYPE and length < <NUM_LIT> ) or <EOL> ( msg == Notification . TYPE and length < <NUM_LIT> ) or <EOL> ( msg == KeepAlive . TYPE and length != <NUM_LIT> ) <EOL> ) : <EOL> raise Notify ( <NUM_LIT:1> , <NUM_LIT:2> , raw_length ) <EOL> length -= <NUM_LIT> <EOL> data = '<STR_LIT>' <EOL> while length : <EOL> if self . connection . pending ( ) : <EOL> delta = self . connection . read ( length ) <EOL> data += delta <EOL> length -= len ( delta ) <EOL> if not data : <EOL> raise Failure ( '<STR_LIT>' ) <EOL> if msg == Notification . TYPE : <EOL> raise Notification ( ord ( data [ <NUM_LIT:0> ] ) , ord ( data [ <NUM_LIT:1> ] ) ) <EOL> if msg == KeepAlive . TYPE : <EOL> return self . KeepAliveFactory ( data ) <EOL> if msg == Open . TYPE : <EOL> return self . OpenFactory ( data ) <EOL> if msg == Update . TYPE : <EOL> if self . neighbor . parse_routes : <EOL> update = self . UpdateFactory ( data ) <EOL> return update <EOL> else : <EOL> return NOP ( '<STR_LIT>' ) <EOL> if self . strict : <EOL> raise Notify ( <NUM_LIT:1> , <NUM_LIT:3> , msg ) <EOL> return NOP ( data ) <EOL> def read_open ( self , _open , ip ) : <EOL> message = self . read_message ( ) <EOL> if message . TYPE == NOP . TYPE : <EOL> return message <EOL> if message . TYPE != Open . TYPE : <EOL> raise Notify ( <NUM_LIT:5> , <NUM_LIT:1> , '<STR_LIT>' % message ) <EOL> if _open . asn . asn4 ( ) and not message . capabilities . announced ( Capabilities . FOUR_BYTES_ASN ) : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:0> , '<STR_LIT>' ) <EOL> self . _asn4 = message . capabilities . announced ( Capabilities . FOUR_BYTES_ASN ) <EOL> if message . asn == AS_TRANS : <EOL> peer_as = message . capabilities [ Capabilities . FOUR_BYTES_ASN ] <EOL> else : <EOL> peer_as = message . asn <EOL> if peer_as != self . neighbor . peer_as : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:2> , '<STR_LIT>' % ( message . asn , self . neighbor . peer_as ) ) <EOL> if message . router_id == RouterID ( '<STR_LIT>' ) : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:3> , '<STR_LIT>' ) <EOL> if message . router_id == self . neighbor . router_id and message . asn == self . neighbor . local_as : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:3> , '<STR_LIT>' % message . router_id ) <EOL> if message . hold_time < <NUM_LIT:3> : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:6> , '<STR_LIT>' % message . hold_time ) <EOL> if message . hold_time >= <NUM_LIT:3> : <EOL> self . neighbor . hold_time = min ( self . neighbor . hold_time , message . hold_time ) <EOL> if message . capabilities . announced ( Capabilities . EXTENDED_MESSAGE ) : <EOL> if self . peer . bgp . message_size : <EOL> self . message_size = self . peer . bgp . message_size <EOL> return message <EOL> def read_keepalive ( self ) : <EOL> message = self . read_message ( ) <EOL> if message . TYPE == NOP . TYPE : <EOL> return message <EOL> if message . TYPE != KeepAlive . TYPE : <EOL> raise Notify ( <NUM_LIT:5> , <NUM_LIT:2> ) <EOL> return message <EOL> def new_open ( self , restarted , asn4 ) : <EOL> if asn4 : <EOL> asn = self . neighbor . local_as <EOL> else : <EOL> asn = AS_TRANS <EOL> o = Open ( <NUM_LIT:4> , asn , self . neighbor . router_id . ip , Capabilities ( ) . default ( self . neighbor , restarted ) , self . neighbor . hold_time ) <EOL> if not self . connection . write ( o . message ( ) ) : <EOL> raise Failure ( '<STR_LIT>' ) <EOL> return o <EOL> def new_keepalive ( self , force = False ) : <EOL> left = int ( self . connection . last_write + self . neighbor . hold_time . keepalive ( ) - time . time ( ) ) <EOL> k = KeepAlive ( ) <EOL> m = k . message ( ) <EOL> if force : <EOL> written = self . connection . write ( k . message ( ) ) <EOL> if not written : <EOL> logger . message ( self . me ( "<STR_LIT>" ) ) <EOL> self . _messages [ self . neighbor . peer_as ] . append ( ( '<STR_LIT>' , m ) ) <EOL> else : <EOL> self . _frozen = <NUM_LIT:0> <EOL> return left , k <EOL> if left <= <NUM_LIT:0> : <EOL> written = self . connection . write ( k . message ( ) ) <EOL> if not written : <EOL> logger . message ( self . me ( "<STR_LIT>" ) ) <EOL> self . _messages [ self . neighbor . peer_as ] . append ( ( '<STR_LIT>' , m ) ) <EOL> else : <EOL> self . _frozen = <NUM_LIT:0> <EOL> return left , k <EOL> return left , None <EOL> def new_notification ( self , notification ) : <EOL> return self . connection . write ( notification . message ( ) ) <EOL> def buffered ( self ) : <EOL> return self . _messages . get ( self . neighbor . peer_as , [ ] ) != [ ] <EOL> def _backlog ( self , maximum = <NUM_LIT:0> ) : <EOL> backlog = self . _messages . get ( self . neighbor . peer_as , [ ] ) <EOL> if backlog : <EOL> if not self . _frozen : <EOL> self . _frozen = time . time ( ) <EOL> if self . _frozen and self . _frozen + ( self . neighbor . hold_time ) < time . time ( ) : <EOL> raise Failure ( '<STR_LIT>' % self . neighbor . peer_as ) <EOL> logger . message ( self . me ( "<STR_LIT>" % ( time . time ( ) - self . _frozen , self . neighbor . hold_time ) ) ) <EOL> nb_backlog = len ( backlog ) <EOL> if nb_backlog > MAX_BACKLOG : <EOL> raise Failure ( '<STR_LIT>' % ( MAX_BACKLOG , self . neighbor . peer_as ) ) <EOL> logger . message ( self . me ( "<STR_LIT>" % ( nb_backlog , MAX_BACKLOG ) ) ) <EOL> count = <NUM_LIT:0> <EOL> while backlog : <EOL> count += <NUM_LIT:1> <EOL> name , update = backlog [ <NUM_LIT:0> ] <EOL> written = self . connection . write ( update ) <EOL> if not written : <EOL> break <EOL> logger . message ( self . me ( "<STR_LIT>" % name ) ) <EOL> backlog . pop ( <NUM_LIT:0> ) <EOL> self . _frozen = <NUM_LIT:0> <EOL> yield count <EOL> if maximum and count >= maximum : <EOL> break <EOL> self . _messages [ self . neighbor . peer_as ] = backlog <EOL> def _announce ( self , name , generator ) : <EOL> def chunked ( generator , size ) : <EOL> chunk = '<STR_LIT>' <EOL> for data in generator : <EOL> if len ( data ) > size : <EOL> raise Failure ( '<STR_LIT>' % size ) <EOL> if len ( chunk ) + len ( data ) <= size : <EOL> chunk += data <EOL> continue <EOL> yield chunk <EOL> chunk = data <EOL> if chunk : <EOL> yield chunk <EOL> count = <NUM_LIT:0> <EOL> for update in chunked ( generator , self . message_size - <NUM_LIT> ) : <EOL> count += <NUM_LIT:1> <EOL> if self . _messages [ self . neighbor . peer_as ] : <EOL> logger . message ( self . me ( "<STR_LIT>" % name ) ) <EOL> self . _messages [ self . neighbor . peer_as ] . append ( ( name , update ) ) <EOL> continue <EOL> written = self . connection . write ( update ) <EOL> if not written : <EOL> logger . message ( self . me ( "<STR_LIT>" % name ) ) <EOL> self . _messages [ self . neighbor . peer_as ] . append ( ( name , update ) ) <EOL> yield count <EOL> def new_announce ( self ) : <EOL> for answer in self . _backlog ( ) : <EOL> yield answer <EOL> asn4 = not not self . peer . open . capabilities . announced ( Capabilities . FOUR_BYTES_ASN ) <EOL> for answer in self . _announce ( '<STR_LIT>' , self . _delta . announce ( asn4 , self . neighbor . local_as , self . neighbor . peer_as ) ) : <EOL> yield answer <EOL> def new_update ( self ) : <EOL> for answer in self . _backlog ( ) : <EOL> yield answer <EOL> asn4 = not not self . peer . open . capabilities . announced ( Capabilities . FOUR_BYTES_ASN ) <EOL> for answer in self . _announce ( '<STR_LIT>' , self . _delta . update ( asn4 , self . neighbor . local_as , self . neighbor . peer_as ) ) : <EOL> yield answer <EOL> def new_eors ( self , families ) : <EOL> for answer in self . _backlog ( ) : <EOL> pass <EOL> eor = EOR ( ) <EOL> eors = eor . eors ( families ) <EOL> for answer in self . _announce ( '<STR_LIT>' , eors ) : <EOL> pass <EOL> def KeepAliveFactory ( self , data ) : <EOL> return KeepAlive ( ) <EOL> def _key_values ( self , name , data ) : <EOL> if len ( data ) < <NUM_LIT:2> : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:0> , "<STR_LIT>" % ( name , hexa ( data ) ) ) <EOL> l = ord ( data [ <NUM_LIT:1> ] ) <EOL> boundary = l + <NUM_LIT:2> <EOL> if len ( data ) < boundary : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:0> , "<STR_LIT>" % ( name , hexa ( data ) ) ) <EOL> key = ord ( data [ <NUM_LIT:0> ] ) <EOL> value = data [ <NUM_LIT:2> : boundary ] <EOL> rest = data [ boundary : ] <EOL> return key , value , rest <EOL> def CapabilitiesFactory ( self , data ) : <EOL> capabilities = Capabilities ( ) <EOL> option_len = ord ( data [ <NUM_LIT:0> ] ) <EOL> if option_len : <EOL> data = data [ <NUM_LIT:1> : ] <EOL> while data : <EOL> key , value , data = self . _key_values ( '<STR_LIT>' , data ) <EOL> if key == Parameter . AUTHENTIFICATION_INFORMATION : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:5> ) <EOL> if key == Parameter . CAPABILITIES : <EOL> while value : <EOL> k , capv , value = self . _key_values ( '<STR_LIT>' , value ) <EOL> if k == Capabilities . MULTIPROTOCOL_EXTENSIONS : <EOL> if k not in capabilities : <EOL> capabilities [ k ] = MultiProtocol ( ) <EOL> afi = AFI ( unpack ( '<STR_LIT>' , capv [ : <NUM_LIT:2> ] ) [ <NUM_LIT:0> ] ) <EOL> safi = SAFI ( ord ( capv [ <NUM_LIT:3> ] ) ) <EOL> capabilities [ k ] . append ( ( afi , safi ) ) <EOL> continue <EOL> if k == Capabilities . GRACEFUL_RESTART : <EOL> restart = unpack ( '<STR_LIT>' , capv [ : <NUM_LIT:2> ] ) [ <NUM_LIT:0> ] <EOL> restart_flag = restart >> <NUM_LIT:12> <EOL> restart_time = restart & Graceful . TIME_MASK <EOL> value_gr = capv [ <NUM_LIT:2> : ] <EOL> families = [ ] <EOL> while value_gr : <EOL> afi = AFI ( unpack ( '<STR_LIT>' , value_gr [ : <NUM_LIT:2> ] ) [ <NUM_LIT:0> ] ) <EOL> safi = SAFI ( ord ( value_gr [ <NUM_LIT:2> ] ) ) <EOL> flag_family = ord ( value_gr [ <NUM_LIT:0> ] ) <EOL> families . append ( ( afi , safi , flag_family ) ) <EOL> value_gr = value_gr [ <NUM_LIT:4> : ] <EOL> capabilities [ k ] = Graceful ( restart_flag , restart_time , families ) <EOL> continue <EOL> if k == Capabilities . FOUR_BYTES_ASN : <EOL> capabilities [ k ] = ASN ( unpack ( '<STR_LIT>' , capv [ : <NUM_LIT:4> ] ) [ <NUM_LIT:0> ] ) <EOL> continue <EOL> if k == Capabilities . ROUTE_REFRESH : <EOL> capabilities [ k ] = RouteRefresh ( ) <EOL> continue <EOL> if k == Capabilities . CISCO_ROUTE_REFRESH : <EOL> capabilities [ k ] = CiscoRouteRefresh ( ) <EOL> continue <EOL> if k == Capabilities . MULTISESSION_BGP : <EOL> capabilities [ k ] = MultiSession ( ) <EOL> continue <EOL> if k == Capabilities . MULTISESSION_BGP_RFC : <EOL> capabilities [ k ] = MultiSession ( ) <EOL> continue <EOL> if k not in capabilities : <EOL> capabilities [ k ] = Unknown ( k , [ ord ( _ ) for _ in capv ] ) <EOL> else : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:0> , '<STR_LIT>' % hex ( key ) ) <EOL> return capabilities <EOL> def OpenFactory ( self , data ) : <EOL> version = ord ( data [ <NUM_LIT:0> ] ) <EOL> if version != <NUM_LIT:4> : <EOL> raise Notify ( <NUM_LIT:2> , <NUM_LIT:1> , data [ <NUM_LIT:0> ] ) <EOL> asn = unpack ( '<STR_LIT>' , data [ <NUM_LIT:1> : <NUM_LIT:3> ] ) [ <NUM_LIT:0> ] <EOL> hold_time = unpack ( '<STR_LIT>' , data [ <NUM_LIT:3> : <NUM_LIT:5> ] ) [ <NUM_LIT:0> ] <EOL> numeric = unpack ( '<STR_LIT>' , data [ <NUM_LIT:5> : <NUM_LIT:9> ] ) [ <NUM_LIT:0> ] <EOL> router_id = "<STR_LIT>" % ( numeric >> <NUM_LIT> , ( numeric >> <NUM_LIT:16> ) & <NUM_LIT> , ( numeric >> <NUM_LIT:8> ) & <NUM_LIT> , numeric & <NUM_LIT> ) <EOL> capabilities = self . CapabilitiesFactory ( data [ <NUM_LIT:9> : ] ) <EOL> return Open ( version , asn , router_id , capabilities , hold_time ) <EOL> def UpdateFactory ( self , data ) : <EOL> length = len ( data ) <EOL> lw , withdrawn , data = defix ( data ) <EOL> if len ( withdrawn ) != lw : <EOL> raise Notify ( <NUM_LIT:3> , <NUM_LIT:1> ) <EOL> la , attribute , announced = defix ( data ) <EOL> if len ( attribute ) != la : <EOL> raise Notify ( <NUM_LIT:3> , <NUM_LIT:1> ) <EOL> if <NUM_LIT:2> + lw + <NUM_LIT:2> + la + len ( announced ) != length : <EOL> raise Notify ( <NUM_LIT:3> , <NUM_LIT:1> ) <EOL> routes = [ ] <EOL> while withdrawn : <EOL> nlri = BGPPrefix ( AFI . ipv4 , withdrawn ) <EOL> route = ReceivedRoute ( nlri , '<STR_LIT>' ) <EOL> withdrawn = withdrawn [ len ( nlri ) : ] <EOL> routes . append ( route ) <EOL> self . mp_routes = [ ] <EOL> attributes = self . AttributesFactory ( attribute ) <EOL> routes . extend ( self . mp_routes ) <EOL> while announced : <EOL> nlri = BGPPrefix ( AFI . ipv4 , announced ) <EOL> route = ReceivedRoute ( nlri , '<STR_LIT>' ) <EOL> route . attributes = attributes <EOL> announced = announced [ len ( nlri ) : ] <EOL> routes . append ( route ) <EOL> if routes : <EOL> return Update ( routes ) <EOL> return NOP ( '<STR_LIT>' ) <EOL> def AttributesFactory ( self , data ) : <EOL> try : <EOL> self . attributes = Attributes ( ) <EOL> return self . _AttributesFactory ( data ) . attributes <EOL> except IndexError : <EOL> raise Notify ( <NUM_LIT:3> , <NUM_LIT:2> , data ) <EOL> def __new_ASPath ( self , data , asn4 = False ) : <EOL> if len ( data ) == <NUM_LIT:0> : <EOL> return ASPath ( asn4 ) <EOL> if asn4 : <EOL> size = <NUM_LIT:4> <EOL> decoder = '<STR_LIT:L>' <EOL> else : <EOL> size = <NUM_LIT:2> <EOL> decoder = '<STR_LIT:H>' <EOL> stype = ord ( data [ <NUM_LIT:0> ] ) <EOL> slen = ord ( data [ <NUM_LIT:1> ] ) <EOL> sdata = data [ <NUM_LIT:2> : <NUM_LIT:2> + ( slen * size ) ] <EOL> ASPS = ASPath ( asn4 , stype ) <EOL> format = '<STR_LIT:!>' + ( decoder * slen ) <EOL> for c in unpack ( format , sdata ) : <EOL> ASPS . add ( c ) <EOL> return ASPS <EOL> def __new_AS4Path ( self , data ) : <EOL> stype = ord ( data [ <NUM_LIT:0> ] ) <EOL> slen = ord ( data [ <NUM_LIT:1> ] ) <EOL> sdata = data [ <NUM_LIT:2> : <NUM_LIT:2> + ( slen * <NUM_LIT:4> ) ] <EOL> ASPS = AS4Path ( stype ) <EOL> format = '<STR_LIT:!>' + ( '<STR_LIT:L>' * slen ) <EOL> for c in unpack ( format , sdata ) : <EOL> ASPS . add ( c ) <EOL> return ASPS <EOL> def __merge_attributes ( self ) : <EOL> as2path = self . attributes [ AttributeID . AS_PATH ] <EOL> as4path = self . attributes [ AttributeID . AS4_PATH ] <EOL> newASPS = ASPath ( True , as2path . asptype ) <EOL> len2 = len ( as2path . aspsegment ) <EOL> len4 = len ( as4path . aspsegment ) <EOL> if len2 < len4 : <EOL> for asn in as4path . aspsegment : <EOL> newASPS . add ( asn ) <EOL> else : <EOL> for asn in as2path . aspsegment [ : - len4 ] : <EOL> newASPS . add ( asn ) <EOL> for asn in as4path . aspsegment : <EOL> newASPS . add ( asn ) <EOL> self . attributes . remove ( AttributeID . AS_PATH ) <EOL> self . attributes . remove ( AttributeID . AS4_PATH ) <EOL> self . attributes . add ( newASPS ) <EOL> def __new_communities ( self , data ) : <EOL> communities = Communities ( ) <EOL> while data : <EOL> community = unpack ( '<STR_LIT>' , data [ : <NUM_LIT:4> ] ) [ <NUM_LIT:0> ] <EOL> data = data [ <NUM_LIT:4> : ] <EOL> if data and len ( data ) < <NUM_LIT:4> : <EOL> raise Notify ( <NUM_LIT:3> , <NUM_LIT:1> , '<STR_LIT>' % str ( [ hex ( ord ( _ ) ) for _ in data ] ) ) <EOL> communities . add ( Community ( community ) ) <EOL> return communities <EOL> def __new_extended_communities ( self , data ) : <EOL> communities = ECommunities ( ) <EOL> while data : <EOL> community = data [ : <NUM_LIT:8> ] <EOL> data = data [ <NUM_LIT:8> : ] <EOL> if data and len ( data ) < <NUM_LIT:8> : <EOL> raise Notify ( <NUM_LIT:3> , <NUM_LIT:1> , '<STR_LIT>' % str ( [ hex ( ord ( _ ) ) for _ in data ] ) ) <EOL> communities . add ( ECommunity . unpackFrom ( community ) ) <EOL> return communities <EOL> def _AttributesFactory ( self , data ) : <EOL> if not data : <EOL> return self <EOL> flag = Flag ( ord ( data [ <NUM_LIT:0> ] ) ) <EOL> code = AttributeID ( ord ( data [ <NUM_LIT:1> ] ) ) <EOL> if flag & Flag . EXTENDED_LENGTH : <EOL> length = unpack ( '<STR_LIT>' , data [ <NUM_LIT:2> : <NUM_LIT:4> ] ) [ <NUM_LIT:0> ] <EOL> offset = <NUM_LIT:4> <EOL> else : <EOL> length = ord ( data [ <NUM_LIT:2> ] ) <EOL> offset = <NUM_LIT:3> <EOL> data = data [ offset : ] <EOL> if code == AttributeID . ORIGIN : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( Origin ( ord ( data [ <NUM_LIT:0> ] ) ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . AS_PATH : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( self . __new_ASPath ( data [ : length ] , self . _asn4 ) ) <EOL> if not self . _asn4 and self . attributes . has ( AttributeID . AS4_PATH ) : <EOL> self . __merge_attributes ( ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . AS4_PATH : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( self . __new_AS4Path ( data [ : length ] ) ) <EOL> if not self . _asn4 and self . attributes . has ( AttributeID . AS_PATH ) : <EOL> self . __merge_attributes ( ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . NEXT_HOP : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( NextHop ( Inet ( AFI . ipv4 , data [ : <NUM_LIT:4> ] ) ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . MED : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( MED ( unpack ( '<STR_LIT>' , data [ : <NUM_LIT:4> ] ) [ <NUM_LIT:0> ] ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . LOCAL_PREF : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( LocalPreference ( unpack ( '<STR_LIT>' , data [ : <NUM_LIT:4> ] ) [ <NUM_LIT:0> ] ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . ORIGINATOR_ID : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( OriginatorId . unpack ( data [ : <NUM_LIT:4> ] ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . PMSI_TUNNEL : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( PMSITunnel . unpack ( data [ : length ] ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . ATOMIC_AGGREGATE : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . AGGREGATOR : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . AS4_AGGREGATOR : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . COMMUNITY : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( self . __new_communities ( data [ : length ] ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . EXTENDED_COMMUNITY : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> self . attributes . add ( self . __new_extended_communities ( data [ : length ] ) ) <EOL> return self . _AttributesFactory ( data [ length : ] ) <EOL> if code == AttributeID . MP_UNREACH_NLRI : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> next_attributes = data [ length : ] <EOL> data = data [ : length ] <EOL> afi , safi = unpack ( '<STR_LIT>' , data [ : <NUM_LIT:3> ] ) <EOL> offset = <NUM_LIT:3> <EOL> if not afi in ( AFI . ipv4 , AFI . ipv6 , AFI . l2vpn ) or ( not safi in ( SAFI . unicast , SAFI . mpls_vpn , SAFI . rtc , SAFI . evpn ) ) : <EOL> raise Exception ( "<STR_LIT>" ) <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> data = data [ offset : ] <EOL> while data : <EOL> if safi == SAFI . unicast : <EOL> route = ReceivedRoute ( BGPPrefix ( afi , data ) , '<STR_LIT>' ) <EOL> elif ( afi == AFI . ipv4 and safi == SAFI . mpls_vpn ) : <EOL> route = ReceivedRoute ( VPNLabelledPrefix . unpack ( afi , safi , data ) , '<STR_LIT>' ) <EOL> elif ( afi == AFI . ipv4 and safi == SAFI . rtc ) : <EOL> route = ReceivedRoute ( RouteTargetConstraint . unpack ( afi , safi , data ) , '<STR_LIT>' ) <EOL> elif ( afi == AFI . l2vpn and safi == SAFI . evpn ) : <EOL> route = ReceivedRoute ( EVPNNLRI . unpack ( data ) , '<STR_LIT>' ) <EOL> else : <EOL> raise Exception ( "<STR_LIT>" ) <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> data = data [ len ( route . nlri ) : ] <EOL> self . mp_routes . append ( route ) <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> if code == AttributeID . MP_REACH_NLRI : <EOL> logger . parser ( '<STR_LIT>' ) <EOL> next_attributes = data [ length : ] <EOL> data = data [ : length ] <EOL> afi , safi = unpack ( '<STR_LIT>' , data [ : <NUM_LIT:3> ] ) <EOL> offset = <NUM_LIT:3> <EOL> if not afi in ( AFI . ipv4 , AFI . ipv6 , AFI . l2vpn ) or ( not safi in ( SAFI . unicast , SAFI . mpls_vpn , SAFI . rtc , SAFI . evpn ) ) : <EOL> raise Exception ( "<STR_LIT>" ) <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> len_nh = ord ( data [ offset ] ) <EOL> offset += <NUM_LIT:1> <EOL> if afi == AFI . ipv4 and safi in ( SAFI . unicast , ) and not len_nh == <NUM_LIT:4> : <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> if afi == AFI . ipv6 and safi in ( SAFI . unicast , ) and not len_nh in ( <NUM_LIT:16> , <NUM_LIT:32> ) : <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> nh = data [ offset : offset + len_nh ] <EOL> offset += len_nh <EOL> if len_nh == <NUM_LIT:32> : <EOL> if nh [ <NUM_LIT:0> ] == chr ( <NUM_LIT> ) : nh = nh [ <NUM_LIT:16> : ] <EOL> elif nh [ <NUM_LIT:16> ] == chr ( <NUM_LIT> ) : nh = nh [ : <NUM_LIT:16> ] <EOL> else : return self . _AttributesFactory ( next_attributes ) <EOL> if len_nh >= <NUM_LIT:16> : nh = socket . inet_ntop ( socket . AF_INET6 , nh ) <EOL> else : <EOL> if ( safi in ( SAFI . mpls_vpn , ) ) : <EOL> nh = socket . inet_ntop ( socket . AF_INET , nh [ <NUM_LIT:8> : ] ) <EOL> else : <EOL> nh = socket . inet_ntop ( socket . AF_INET , nh ) <EOL> nb_snpa = ord ( data [ offset ] ) <EOL> offset += <NUM_LIT:1> <EOL> snpas = [ ] <EOL> for _ in range ( nb_snpa ) : <EOL> len_snpa = ord ( offset ) <EOL> offset += <NUM_LIT:1> <EOL> snpas . append ( data [ offset : offset + len_snpa ] ) <EOL> offset += len_snpa <EOL> data = data [ offset : ] <EOL> while data : <EOL> if safi == SAFI . unicast : <EOL> route = ReceivedRoute ( BGPPrefix ( afi , data ) , '<STR_LIT>' ) <EOL> elif ( afi == AFI . ipv4 and safi == SAFI . mpls_vpn ) : <EOL> route = ReceivedRoute ( VPNLabelledPrefix . unpack ( afi , safi , data ) , '<STR_LIT>' ) <EOL> elif ( afi == AFI . ipv4 and safi == SAFI . rtc ) : <EOL> route = ReceivedRoute ( RouteTargetConstraint . unpack ( afi , safi , data ) , '<STR_LIT>' ) <EOL> elif ( afi == AFI . l2vpn and safi == SAFI . evpn ) : <EOL> route = ReceivedRoute ( EVPNNLRI . unpack ( data ) , '<STR_LIT>' ) <EOL> else : <EOL> raise Exception ( "<STR_LIT>" ) <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> data = data [ len ( route . nlri ) : ] <EOL> route . attributes = self . attributes <EOL> route . attributes . add ( NextHop ( to_IP ( nh ) ) ) <EOL> self . mp_routes . append ( route ) <EOL> return self . _AttributesFactory ( next_attributes ) <EOL> logger . warning ( "<STR_LIT>" % ( str ( code ) , [ hex ( ord ( _ ) ) for _ in data ] ) , '<STR_LIT>' ) <EOL> return self . _AttributesFactory ( data [ length : ] ) </s>
