Passed
Pull Request — master (#923)
by
unknown
12:29
created

ExtendedCommunity.unpack()   A

Complexity

Conditions 2

Size

Total Lines 10
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nop 2
dl 0
loc 10
rs 9.95
c 0
b 0
f 0
1
# encoding: utf-8
2
"""
3
community.py
4
5
Created by Thomas Mangin on 2009-11-05.
6
Copyright (c) 2009-2017 Exa Networks. All rights reserved.
7
License: 3-clause BSD. (See the COPYRIGHT file)
8
"""
9
10
from exabgp.util import ordinal
11
from exabgp.bgp.message.update.attribute import Attribute
12
13
from struct import pack
14
15
# ======================================================= ExtendedCommunity (16)
16
# XXX: Should subclasses register with transitivity ?
17
18
19
class ExtendedCommunityBase (Attribute):
20
	COMMUNITY_TYPE    = 0x00  # MUST be redefined by subclasses
21
	COMMUNITY_SUBTYPE = 0x00  # MUST be redefined by subclasses
22
	NON_TRANSITIVE    = 0x40
23
24
	registered_extended = {}
25
26
	@classmethod
27
	def register (cls, klass):
28
		cls.registered_extended[(klass.COMMUNITY_TYPE & 0x0F,klass.COMMUNITY_SUBTYPE)] = klass
29
		return klass
30
31
	# size of value for data (boolean: is extended)
32
	length_value = {False:7, True:6}
33
	name = {False: 'regular', True: 'extended'}
34
35
	__slots__ = ['community']
36
37
	def __init__ (self, community):
38
		# Two top bits are iana and transitive bits
39
		self.community = community
40
		self.klass = None
41
42
	def __eq__(self, other):
43
		return \
44
			self.ID == other.ID and \
45
			self.FLAG == other.FLAG and \
46
			self.community == other.community
47
48
	def __ne__(self, other):
49
		return not self.__eq__(other)
50
51
	def __lt__ (self, other):
52
		return self.community < other.community
53
54
	def __le__ (self, other):
55
		return self.community <= other.community
56
57
	def __gt__ (self, other):
58
		return self.community > other.community
59
60
	def __ge__ (self, other):
61
		return self.community >= other.community
62
63
	def iana (self):
64
		return not not (self.community[0] & 0x80)
65
66
	def transitive (self):
67
		# bit set means "not transitive"
68
		# RFC4360:
69
		#   T - Transitive bit
70
		#     Value 0: The community is transitive across ASes
71
		#     Value 1: The community is non-transitive across ASes
72
		return not (self.community[0] & 0x40)
73
74
	def pack (self, negotiated=None):
75
		return self.community
76
77
	def _subtype (self, transitive=True):
78
		# if not transitive -> set the 'transitive' bit, as per RFC4360
79
		return pack(
80
			'!BB',
81
			self.COMMUNITY_TYPE if transitive else self.COMMUNITY_TYPE | self.NON_TRANSITIVE,
82
			self.COMMUNITY_SUBTYPE
83
		)
84
85
	def json (self):
86
		h = 0x00
87
		for byte in self.community:
88
			h <<= 8
89
			h += ordinal(byte)
90
		s = self.klass.__repr__(self) if self.klass else ''
91
		return '{ "value": %s, "string": "%s" }' % (h,s)
92
93
	def __repr__ (self):
94
		if self.klass:
95
			return self.klass.__repr__(self)
96
		h = 0x00
97
		for byte in self.community:
98
			h <<= 8
99
			h += ordinal(byte)
100
		return "0x%016X" % h
101
102
	def __hash__ (self):
103
		return hash(self.community)
104
105
	@staticmethod
106
	def unpack (data, negotiated=None):
107
		# 30/02/12 Quagga communities for soo and rt are not transitive when 4360 says they must be, hence the & 0x0FFF
108
		community = (ordinal(data[0]) & 0x0F,ordinal(data[1]))
109
		if community in ExtendedCommunity.registered_extended:
110
			klass = ExtendedCommunity.registered_extended[community]
111
			instance = klass.unpack(data)
112
			instance.klass = klass
113
			return instance
114
		return ExtendedCommunity(data)
115
116
class ExtendedCommunity (ExtendedCommunityBase):
117
	ID = Attribute.CODE.EXTENDED_COMMUNITY
118
	FLAG = Attribute.Flag.TRANSITIVE | Attribute.Flag.OPTIONAL
119
120
	def __len__ (self):
121
		return 8
122
123
124
class ExtendedCommunityIPv6 (ExtendedCommunityBase):
125
	ID = Attribute.CODE.IPV6_EXTENDED_COMMUNITY
126
	FLAG = Attribute.Flag.TRANSITIVE | Attribute.Flag.OPTIONAL
127
128
	def __len__ (self):
129
		return 20
130