~ubuntu-branches/ubuntu/utopic/exabgp/utopic

« back to all changes in this revision

Viewing changes to lib/exabgp/bgp/message/update/attribute/attributes.py

  • Committer: Package Import Robot
  • Author(s): Henry-Nicolas Tourneur
  • Date: 2014-03-08 19:07:00 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20140308190700-xjbibpg1g6001c9x
Tags: 3.3.1-1
* New upstream release
* Bump python minimal required version (2.7)
* Closes: #726066 Debian packaging improvements proposed by Vincent Bernat
* Closes: #703774 not existent rundir (/var/run/exabgp) after reboot

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# encoding: utf-8
2
 
"""
3
 
set.py
4
 
 
5
 
Created by Thomas Mangin on 2010-01-16.
6
 
Copyright (c) 2009-2013  Exa Networks. All rights reserved.
7
 
"""
8
 
 
9
 
from struct import unpack,error
10
 
 
11
 
from exabgp.structure.utils import dump
12
 
from exabgp.structure.environment import environment
13
 
from exabgp.structure.cache import Cache
14
 
 
15
 
from exabgp.protocol.family import AFI,SAFI
16
 
 
17
 
from exabgp.bgp.message.open.asn import ASN,AS_TRANS
18
 
from exabgp.bgp.message.notification import Notify
19
 
from exabgp.bgp.message.update.nlri.eor import RouteEOR
20
 
from exabgp.bgp.message.update.attribute.id import AttributeID as AID
21
 
from exabgp.bgp.message.update.attribute.flag import Flag
22
 
from exabgp.bgp.message.update.attribute.origin import Origin
23
 
from exabgp.bgp.message.update.attribute.aspath import ASPath,AS4Path
24
 
from exabgp.bgp.message.update.attribute.nexthop import cachedNextHop
25
 
from exabgp.bgp.message.update.attribute.med import MED
26
 
from exabgp.bgp.message.update.attribute.localpref import LocalPreference
27
 
from exabgp.bgp.message.update.attribute.aggregator import Aggregator
28
 
from exabgp.bgp.message.update.attribute.atomicaggregate import AtomicAggregate
29
 
from exabgp.bgp.message.update.attribute.originatorid import OriginatorID
30
 
from exabgp.bgp.message.update.attribute.clusterlist import ClusterList
31
 
from exabgp.bgp.message.update.attribute.communities import cachedCommunity,Communities,ECommunity,ECommunities
32
 
 
33
 
from exabgp.structure.log import Logger,LazyFormat
34
 
 
35
 
 
36
 
# =================================================================== Attributes
37
 
 
38
 
class MultiAttributes (list):
39
 
        def __init__ (self,attribute):
40
 
                list.__init__(self)
41
 
                self.ID = attribute.ID
42
 
                self.FLAG = attribute.FLAG
43
 
                self.MULTIPLE = True
44
 
                self.append(attribute)
45
 
 
46
 
        def pack (self):
47
 
                r = []
48
 
                for attribute in self:
49
 
                        r.append(attribute.pack())
50
 
                return ''.join(r)
51
 
 
52
 
        def __len__ (self):
53
 
                return len(self.pack())
54
 
 
55
 
        def __str__ (self):
56
 
                return 'MultiAttibutes(%s)' % ' '.join(str(_) for _ in self)
57
 
 
58
 
class Attributes (dict):
59
 
        routeFactory = None
60
 
        autocomplete = True
61
 
        cache = {}
62
 
 
63
 
        def __init__ (self):
64
 
                self._str = ''
65
 
                self.cache_attributes = environment.settings().cache.attributes
66
 
 
67
 
        def has (self,k):
68
 
                return k in self
69
 
 
70
 
        def add_from_cache (self,attributeid,data):
71
 
                if data in self.cache.setdefault(attributeid,Cache()):
72
 
                        self.add(self.cache[attributeid].retrieve(data))
73
 
                        return True
74
 
                return False
75
 
 
76
 
        def add (self,attribute,data=None):
77
 
                self._str = ''
78
 
                if data and self.cache_attributes:
79
 
                        self.cache[attribute.ID].cache(data,attribute)
80
 
                if attribute.MULTIPLE:
81
 
                        if self.has(attribute.ID):
82
 
                                self[attribute.ID].append(attribute)
83
 
                        else:
84
 
                                self[attribute.ID] = MultiAttributes(attribute)
85
 
                else:
86
 
                        self[attribute.ID] = attribute
87
 
 
88
 
        def remove (self,attrid):
89
 
                self.pop(attrid)
90
 
 
91
 
        def _as_path (self,asn4,asp):
92
 
                # if the peer does not understand ASN4, we need to build a transitive AS4_PATH
93
 
                if asn4:
94
 
                        return asp.pack(True)
95
 
 
96
 
                as2_seq = [_ if not _.asn4() else AS_TRANS for _ in asp.as_seq]
97
 
                as2_set = [_ if not _.asn4() else AS_TRANS for _ in asp.as_set]
98
 
 
99
 
                message = ASPath(as2_seq,as2_set).pack(False)
100
 
                if AS_TRANS in as2_seq or AS_TRANS in as2_set:
101
 
                        message += AS4Path(asp.as_seq,asp.as_set).pack()
102
 
                return message
103
 
 
104
 
        def pack (self,asn4,local_asn,peer_asn):
105
 
                ibgp = (local_asn == peer_asn)
106
 
                # we do not store or send MED
107
 
                message = ''
108
 
 
109
 
                if AID.ORIGIN in self:
110
 
                        message += self[AID.ORIGIN].pack()
111
 
                elif self.autocomplete:
112
 
                        message += Origin(Origin.IGP).pack()
113
 
 
114
 
                if AID.AS_PATH in self:
115
 
                        asp = self[AID.AS_PATH]
116
 
                        message += self._as_path(asn4,asp)
117
 
                elif self.autocomplete:
118
 
                        if ibgp:
119
 
                                asp = ASPath([],[])
120
 
                        else:
121
 
                                asp = ASPath([local_asn,],[])
122
 
                        message += self._as_path(asn4,asp)
123
 
                else:
124
 
                        raise RuntimeError('Generated routes must always have an AS_PATH ')
125
 
 
126
 
                if AID.NEXT_HOP in self:
127
 
                        afi = self[AID.NEXT_HOP].afi
128
 
                        safi = self[AID.NEXT_HOP].safi
129
 
                        if afi == AFI.ipv4 and safi in [SAFI.unicast, SAFI.multicast]:
130
 
                                message += self[AID.NEXT_HOP].pack()
131
 
 
132
 
                if AID.MED in self:
133
 
                        if local_asn != peer_asn:
134
 
                                message += self[AID.MED].pack()
135
 
 
136
 
                if ibgp:
137
 
                        if AID.LOCAL_PREF in self:
138
 
                                message += self[AID.LOCAL_PREF].pack()
139
 
                        else:
140
 
                                # '\x00\x00\x00d' is 100 packed in long network bytes order
141
 
                                message += LocalPreference('\x00\x00\x00d').pack()
142
 
 
143
 
                # This generate both AGGREGATOR and AS4_AGGREGATOR
144
 
                if AID.AGGREGATOR in self:
145
 
                        aggregator = self[AID.AGGREGATOR]
146
 
                        message += aggregator.pack(asn4)
147
 
 
148
 
                for attribute in [
149
 
                        AID.ATOMIC_AGGREGATE,
150
 
                        AID.COMMUNITY,
151
 
                        AID.ORIGINATOR_ID,
152
 
                        AID.CLUSTER_LIST,
153
 
                        AID.EXTENDED_COMMUNITY
154
 
                ]:
155
 
                        if attribute in self:
156
 
                                message += self[attribute].pack()
157
 
 
158
 
                return message
159
 
 
160
 
        def json (self):
161
 
                r = []
162
 
                if self.has(AID.NEXT_HOP):           r.append('"next-hop": "%s"' % str(self[AID.NEXT_HOP]))
163
 
                if self.has(AID.ORIGIN):             r.append('"origin": "%s"' % str(self[AID.ORIGIN]))
164
 
                if self.has(AID.AS_PATH):            r.append('"as-path": %s' % self[AID.AS_PATH].json())
165
 
                if self.has(AID.LOCAL_PREF):         r.append('"local-preference": %s' % self[AID.LOCAL_PREF])
166
 
                if self.has(AID.AGGREGATOR):         r.append('"aggregator" : "%s"' % self[AID.AGGREGATOR])
167
 
                if self.has(AID.MED):                r.append('"med": %s' % self[AID.MED])
168
 
                if self.has(AID.COMMUNITY):          r.append('"community": %s' % self[AID.COMMUNITY].json())
169
 
                if self.has(AID.ORIGINATOR_ID):      r.append('"originator-id": "%s"' % str(self[AID.ORIGINATOR_ID]))
170
 
                if self.has(AID.CLUSTER_LIST):       r.append('"cluster-list": %s' % self[AID.CLUSTER_LIST].json())
171
 
                if self.has(AID.EXTENDED_COMMUNITY): r.append('"extended-community": %s' % self[AID.EXTENDED_COMMUNITY].json())
172
 
                r.append('"atomic-aggregate": %s' % ('true' if self.has(AID.ATOMIC_AGGREGATE) else 'false'))
173
 
                return ", ".join(r)
174
 
 
175
 
        def __str__ (self):
176
 
                if self._str:
177
 
                        return self._str
178
 
 
179
 
                next_hop = ' next-hop %s' % str(self[AID.NEXT_HOP]) if self.has(AID.NEXT_HOP) else ''
180
 
                origin = ' origin %s' % str(self[AID.ORIGIN]) if self.has(AID.ORIGIN) else ''
181
 
                aspath = ' as-path %s' % str(self[AID.AS_PATH]) if self.has(AID.AS_PATH) else ''
182
 
                local_pref = ' local-preference %s' % self[AID.LOCAL_PREF] if self.has(AID.LOCAL_PREF) else ''
183
 
                aggregator = ' aggregator ( %s )' % self[AID.AGGREGATOR] if self.has(AID.AGGREGATOR) else ''
184
 
                atomic = ' atomic-aggregate' if self.has(AID.ATOMIC_AGGREGATE) else ''
185
 
                med = ' med %s' % self[AID.MED] if self.has(AID.MED) else ''
186
 
                communities = ' community %s' % str(self[AID.COMMUNITY]) if self.has(AID.COMMUNITY) else ''
187
 
                originator_id = ' originator-id %s' % str(self[AID.ORIGINATOR_ID]) if self.has(AID.ORIGINATOR_ID) else ''
188
 
                cluster_list = ' cluster-list %s' % str(self[AID.CLUSTER_LIST]) if self.has(AID.CLUSTER_LIST) else ''
189
 
                ecommunities = ' extended-community %s' % str(self[AID.EXTENDED_COMMUNITY]) if self.has(AID.EXTENDED_COMMUNITY) else ''
190
 
 
191
 
                self._str = "%s%s%s%s%s%s%s%s%s%s%s" % (
192
 
                        next_hop,origin,aspath,local_pref,atomic,aggregator,med,communities,ecommunities,originator_id,cluster_list
193
 
                )
194
 
                return self._str
195
 
 
196
 
 
197
 
        def factory (self,negotiated,data):
198
 
                try:
199
 
                        # XXX: hackish for now
200
 
                        self.mp_announce = []
201
 
                        self.mp_withdraw = []
202
 
 
203
 
                        self.negotiated = negotiated
204
 
                        self._factory(data)
205
 
                        if AID.AS_PATH in self and AID.AS4_PATH in self:
206
 
                                self.__merge_attributes()
207
 
                        return self
208
 
                except IndexError:
209
 
                        raise Notify(3,2,data)
210
 
 
211
 
        def _factory (self,data):
212
 
                if not data:
213
 
                        return self
214
 
 
215
 
                # We do not care if the attribute are transitive or not as we do not redistribute
216
 
                flag = Flag(ord(data[0]))
217
 
                code = AID(ord(data[1]))
218
 
 
219
 
                if flag & Flag.EXTENDED_LENGTH:
220
 
                        length = unpack('!H',data[2:4])[0]
221
 
                        offset = 4
222
 
                else:
223
 
                        length = ord(data[2])
224
 
                        offset = 3
225
 
 
226
 
                data = data[offset:]
227
 
                next = data[length:]
228
 
                attribute = data[:length]
229
 
 
230
 
                logger = Logger()
231
 
                logger.parser(LazyFormat("parsing flag %x type %02x (%s) len %02x %s" % (flag,int(code),code,length,'payload ' if length else ''),dump,data[:length]))
232
 
 
233
 
                if code == AID.ORIGIN:
234
 
                        # This if block should never be called anymore ...
235
 
                        if not self.add_from_cache(code,attribute):
236
 
                                self.add(Origin(ord(attribute)),attribute)
237
 
                        return self._factory(next)
238
 
 
239
 
                # only 2-4% of duplicated data - is it worth to cache ?
240
 
                if code == AID.AS_PATH:
241
 
                        if length:
242
 
                                # we store the AS4_PATH as AS_PATH, do not over-write
243
 
                                if not self.has(code):
244
 
                                        if not self.add_from_cache(code,attribute):
245
 
                                                self.add(self.__new_ASPath(attribute),attribute)
246
 
                        return self._factory(next)
247
 
 
248
 
                if code == AID.AS4_PATH:
249
 
                        if length:
250
 
                                # ignore the AS4_PATH on new spekers as required by RFC 4893 section 4.1
251
 
                                if not self.negotiated.asn4:
252
 
                                        # This replace the old AS_PATH
253
 
                                        if not self.add_from_cache(code,attribute):
254
 
                                                self.add(self.__new_ASPath4(attribute),attribute)
255
 
                        return self._factory(next)
256
 
 
257
 
                if code == AID.NEXT_HOP:
258
 
                        if not self.add_from_cache(code,attribute):
259
 
                                self.add(cachedNextHop(AFI.ipv4,SAFI.unicast_multicast,attribute),attribute)
260
 
                        return self._factory(next)
261
 
 
262
 
                if code == AID.MED:
263
 
                        if not self.add_from_cache(code,attribute):
264
 
                                self.add(MED(attribute),attribute)
265
 
                        return self._factory(next)
266
 
 
267
 
                if code == AID.LOCAL_PREF:
268
 
                        if not self.add_from_cache(code,attribute):
269
 
                                self.add(LocalPreference(attribute),attribute)
270
 
                        return self._factory(next)
271
 
 
272
 
                if code == AID.ATOMIC_AGGREGATE:
273
 
                        if not self.add_from_cache(code,attribute):
274
 
                                raise Notify(3,2,'invalid ATOMIC_AGGREGATE %s' % [hex(ord(_)) for _ in attribute])
275
 
                        return self._factory(next)
276
 
 
277
 
                if code == AID.AGGREGATOR:
278
 
                        # AS4_AGGREGATOR are stored as AGGREGATOR - so do not overwrite if exists
279
 
                        if not self.has(code):
280
 
                                if not self.add_from_cache(AID.AGGREGATOR,attribute):
281
 
                                        self.add(Aggregator(attribute),attribute)
282
 
                        return self._factory(next)
283
 
 
284
 
                if code == AID.AS4_AGGREGATOR:
285
 
                        if not self.add_from_cache(AID.AGGREGATOR,attribute):
286
 
                                self.add(Aggregator(attribute),attribute)
287
 
                        return self._factory(next)
288
 
 
289
 
                if code == AID.COMMUNITY:
290
 
                        if not self.add_from_cache(code,attribute):
291
 
                                self.add(self.__new_communities(attribute),attribute)
292
 
                        return self._factory(next)
293
 
 
294
 
                if code == AID.ORIGINATOR_ID:
295
 
                        if not self.add_from_cache(code,attribute):
296
 
                                self.add(OriginatorID(AFI.ipv4,SAFI.unicast,data[:4]),attribute)
297
 
                        return self._factory(next)
298
 
 
299
 
                if code == AID.CLUSTER_LIST:
300
 
                        if not self.add_from_cache(code,attribute):
301
 
                                self.add(ClusterList(attribute),attribute)
302
 
                        return self._factory(next)
303
 
 
304
 
                if code == AID.EXTENDED_COMMUNITY:
305
 
                        if not self.add_from_cache(code,attribute):
306
 
                                self.add(self.__new_extended_communities(attribute),attribute)
307
 
                        return self._factory(next)
308
 
 
309
 
                if code == AID.MP_UNREACH_NLRI:
310
 
                        # -- Reading AFI/SAFI
311
 
                        data = data[:length]
312
 
                        afi,safi = unpack('!HB',data[:3])
313
 
                        offset = 3
314
 
                        data = data[offset:]
315
 
 
316
 
                        if (afi,safi) not in self.negotiated.families:
317
 
                                raise Notify(3,0,'presented a non-negotiated family %d/%d' % (afi,safi))
318
 
 
319
 
                        # Is the peer going to send us some Path Information with the route (AddPath)
320
 
                        addpath = self.negotiated.addpath.receive(afi,safi)
321
 
 
322
 
                        # XXX: we do assume that it is an EOR. most likely harmless
323
 
                        if not data:
324
 
                                self.mp_withdraw.append(RouteEOR(afi,safi,'announced'))
325
 
                                return self._factory(next)
326
 
 
327
 
                        while data:
328
 
                                route = self.routeFactory(afi,safi,data,addpath,'withdrawn')
329
 
                                route.attributes = self
330
 
                                self.mp_withdraw.append(route)
331
 
                                data = data[len(route.nlri):]
332
 
                        return self._factory(next)
333
 
 
334
 
                if code == AID.MP_REACH_NLRI:
335
 
                        data = data[:length]
336
 
                        # -- Reading AFI/SAFI
337
 
                        afi,safi = unpack('!HB',data[:3])
338
 
                        offset = 3
339
 
 
340
 
                        # we do not want to accept unknown families
341
 
                        if (afi,safi) not in self.negotiated.families:
342
 
                                raise Notify(3,0,'presented a non-negotiated family %d/%d' % (afi,safi))
343
 
 
344
 
                        # -- Reading length of next-hop
345
 
                        len_nh = ord(data[offset])
346
 
                        offset += 1
347
 
 
348
 
                        rd = 0
349
 
 
350
 
                        # check next-hope size
351
 
                        if afi == AFI.ipv4:
352
 
                                if safi in (SAFI.unicast,SAFI.multicast):
353
 
                                        if len_nh != 4:
354
 
                                                raise Notify(3,0,'invalid ipv4 unicast/multicast next-hop length %d expected 4' % len_nh)
355
 
                                if safi in (SAFI.mpls_vpn,):
356
 
                                        if len_nh != 12:
357
 
                                                raise Notify(3,0,'invalid ipv4 mpls_vpn next-hop length %d expected 12' % len_nh)
358
 
                                        rd = 8
359
 
                                size = 4
360
 
                        elif afi == AFI.ipv6:
361
 
                                if safi in (SAFI.unicast,):
362
 
                                        if len_nh not in (16,32):
363
 
                                                raise Notify(3,0,'invalid ipv6 unicast next-hop length %d expected 16 or 32' % len_nh)
364
 
                                if safi in (SAFI.mpls_vpn,):
365
 
                                        if len_nh not in (24,40):
366
 
                                                raise Notify(3,0,'invalid ipv6 mpls_vpn next-hop length %d expected 24 or 40' % len_nh)
367
 
                                        rd = 8
368
 
                                size = 16
369
 
 
370
 
                        # -- Reading next-hop
371
 
                        nh = data[offset+rd:offset+rd+size]
372
 
 
373
 
                        # chech the RD is well zeo
374
 
                        if rd and sum([int(ord(_)) for _ in data[offset:8]]) != 0:
375
 
                                raise Notify(3,0,"MP_REACH_NLRI next-hop's route-distinguisher must be zero")
376
 
 
377
 
                        offset += len_nh
378
 
 
379
 
                        # Skip a reserved bit as somone had to bug us !
380
 
                        reserved = ord(data[offset])
381
 
                        offset += 1
382
 
 
383
 
                        if reserved != 0:
384
 
                                raise Notify(3,0,'the reserved bit of MP_REACH_NLRI is not zero')
385
 
 
386
 
                        # Is the peer going to send us some Path Information with the route (AddPath)
387
 
                        addpath = self.negotiated.addpath.receive(afi,safi)
388
 
 
389
 
                        # Reading the NLRIs
390
 
                        data = data[offset:]
391
 
 
392
 
                        while data:
393
 
                                route = self.routeFactory(afi,safi,data,addpath,'announced')
394
 
                                if not route.attributes.add_from_cache(AID.NEXT_HOP,nh):
395
 
                                        route.attributes.add(cachedNextHop(afi,safi,nh),nh)
396
 
                                self.mp_announce.append(route)
397
 
                                data = data[len(route.nlri):]
398
 
                        return self._factory(next)
399
 
 
400
 
                logger.parser('ignoring attribute')
401
 
                return self._factory(next)
402
 
 
403
 
        def __merge_attributes (self):
404
 
                as2path = self[AID.AS_PATH]
405
 
                as4path = self[AID.AS4_PATH]
406
 
                self.remove(AID.AS_PATH)
407
 
                self.remove(AID.AS4_PATH)
408
 
 
409
 
                # this key is unique as index length is a two header, plus a number of ASN of size 2 or 4
410
 
                # so adding the : make the length odd and unique
411
 
                key = "%s:%s" % (as2path.index, as4path.index)
412
 
 
413
 
                # found a cache copy
414
 
                if self.add_from_cache(AID.AS_PATH,key):
415
 
                        return
416
 
 
417
 
                as_seq = []
418
 
                as_set = []
419
 
 
420
 
                len2 = len(as2path.as_seq)
421
 
                len4 = len(as4path.as_seq)
422
 
 
423
 
                # RFC 4893 section 4.2.3
424
 
                if len2 < len4:
425
 
                        as_seq = as2path.as_seq
426
 
                else:
427
 
                        as_seq = as2path.as_seq[:-len4]
428
 
                        as_seq.extend(as4path.as_seq)
429
 
 
430
 
                len2 = len(as2path.as_set)
431
 
                len4 = len(as4path.as_set)
432
 
 
433
 
                if len2 < len4:
434
 
                        as_set = as4path.as_set
435
 
                else:
436
 
                        as_set = as2path.as_set[:-len4]
437
 
                        as_set.extend(as4path.as_set)
438
 
 
439
 
                aspath = ASPath(as_seq,as_set)
440
 
                self.add(aspath,key)
441
 
 
442
 
        def __new_communities (self,data):
443
 
                communities = Communities()
444
 
                while data:
445
 
                        if data and len(data) < 4:
446
 
                                raise Notify(3,1,'could not decode community %s' % str([hex(ord(_)) for _ in data]))
447
 
                        communities.add(cachedCommunity(data[:4]))
448
 
                        data = data[4:]
449
 
                return communities
450
 
 
451
 
        def __new_extended_communities (self,data):
452
 
                communities = ECommunities()
453
 
                while data:
454
 
                        if data and len(data) < 8:
455
 
                                raise Notify(3,1,'could not decode extended community %s' % str([hex(ord(_)) for _ in data]))
456
 
                        communities.add(ECommunity(data[:8]))
457
 
                        data = data[8:]
458
 
                return communities
459
 
 
460
 
        def __new_aspaths (self,data,asn4,klass):
461
 
                as_set = []
462
 
                as_seq = []
463
 
                backup = data
464
 
 
465
 
                unpacker = {
466
 
                        False : '!H',
467
 
                        True  : '!L',
468
 
                }
469
 
                size = {
470
 
                        False: 2,
471
 
                        True : 4,
472
 
                }
473
 
                as_choice = {
474
 
                        ASPath.AS_SEQUENCE : as_seq,
475
 
                        ASPath.AS_SET      : as_set,
476
 
                }
477
 
 
478
 
                upr = unpacker[asn4]
479
 
                length = size[asn4]
480
 
 
481
 
                try:
482
 
 
483
 
                        while data:
484
 
                                stype = ord(data[0])
485
 
                                slen  = ord(data[1])
486
 
 
487
 
                                if stype not in (ASPath.AS_SET, ASPath.AS_SEQUENCE):
488
 
                                        raise Notify(3,11,'invalid AS Path type sent %d' % stype)
489
 
 
490
 
                                end = 2+(slen*length)
491
 
                                sdata = data[2:end]
492
 
                                data = data[end:]
493
 
                                asns = as_choice[stype]
494
 
 
495
 
                                for i in range(slen):
496
 
                                        asn = unpack(upr,sdata[:length])[0]
497
 
                                        asns.append(ASN(asn))
498
 
                                        sdata = sdata[length:]
499
 
 
500
 
                except IndexError:
501
 
                        raise Notify(3,11,'not enough data to decode AS_PATH or AS4_PATH')
502
 
                except error:  # struct
503
 
                        raise Notify(3,11,'not enough data to decode AS_PATH or AS4_PATH')
504
 
 
505
 
                return klass(as_seq,as_set,backup)
506
 
 
507
 
        def __new_ASPath (self,data):
508
 
                return self.__new_aspaths(data,self.negotiated.asn4,ASPath)
509
 
 
510
 
        def __new_ASPath4 (self,data):
511
 
                return self.__new_aspaths(data,True,AS4Path)
512
 
 
513
 
if not Attributes.cache:
514
 
        for attribute in AID._str:
515
 
                Attributes.cache[attribute] = Cache()
516
 
 
517
 
        # There can only be one, build it now :)
518
 
        Attributes.cache[AID.ATOMIC_AGGREGATE][''] = AtomicAggregate()
519
 
 
520
 
        IGP = Origin(Origin.IGP)
521
 
        EGP = Origin(Origin.EGP)
522
 
        INC = Origin(Origin.INCOMPLETE)
523
 
 
524
 
        Attributes.cache[AID.ORIGIN][IGP.pack()] = IGP
525
 
        Attributes.cache[AID.ORIGIN][EGP.pack()] = EGP
526
 
        Attributes.cache[AID.ORIGIN][INC.pack()] = INC
527