summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYAMAMOTO Takashi <yamamoto@valinux.co.jp>2013-11-11 14:43:22 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2013-11-11 22:04:39 +0900
commite7d7e5d7f26570bb51701dd76d90a358948661f3 (patch)
treef3269b0c6fa59febf95d82f367533db77c0d1211
parent12bc3e51b336532fb4f11e39c16921b2afa1e0f9 (diff)
bgp: implement extended communities
RFC 4360 and RFC 5668 Signed-off-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/lib/packet/bgp.py189
1 files changed, 183 insertions, 6 deletions
diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index d4780f6f..3f63290d 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -22,7 +22,6 @@ RFC 4271 BGP-4
# - notify data
# - notify subcode constants
# - RFC 3107 Carrying Label Information in BGP-4
-# - RFC 4360 BGP Extended Communities Attribute
# - RFC 4364 BGP/MPLS IP Virtual Private Networks (VPNs)
# - RFC 4486 Subcodes for BGP Cease Notification Message
@@ -74,6 +73,7 @@ BGP_ATTR_TYPE_AGGREGATOR = 7 # AS number and IPv4 address
BGP_ATTR_TYPE_COMMUNITIES = 8 # RFC 1997
BGP_ATTR_TYPE_MP_REACH_NLRI = 14 # RFC 4760
BGP_ATTR_TYPE_MP_UNREACH_NLRI = 15 # RFC 4760
+BGP_ATTR_TYPE_EXTENDED_COMMUNITIES = 16 # RFC 4360
BGP_ATTR_TYPE_AS4_PATH = 17 # RFC 4893
BGP_ATTR_TYPE_AS4_AGGREGATOR = 18 # RFC 4893
@@ -84,6 +84,10 @@ BGP_COMMUNITY_NO_EXPORT = 0xffffff01
BGP_COMMUNITY_NO_ADVERTISE = 0xffffff02
BGP_COMMUNITY_NO_EXPORT_SUBCONFED = 0xffffff03
+# RFC 4360
+BGP_EXTENDED_COMMUNITY_ROUTE_TARGET = 0x02
+BGP_EXTENDED_COMMUNITY_ROUTE_ORIGIN = 0x03
+
def pad(bin, len_):
assert len(bin) <= len_
@@ -158,17 +162,30 @@ class _IPAddrPrefix(_AddrPrefix):
class _Value(object):
_VALUE_PACK_STR = None
+ _VALUE_FIELDS = ['value']
+
+ @staticmethod
+ def do_init(cls, self, kwargs, **extra_kwargs):
+ ourfields = {}
+ for f in cls._VALUE_FIELDS:
+ v = kwargs[f]
+ del kwargs[f]
+ ourfields[f] = v
+ kwargs.update(extra_kwargs)
+ super(cls, self).__init__(**kwargs)
+ self.__dict__.update(ourfields)
@classmethod
def parse_value(cls, buf):
- (value,) = struct.unpack_from(cls._VALUE_PACK_STR, buffer(buf))
- return {
- 'value': value
- }
+ values = struct.unpack_from(cls._VALUE_PACK_STR, buffer(buf))
+ return dict(zip(cls._VALUE_FIELDS, values))
def serialize_value(self):
+ args = []
+ for f in self._VALUE_FIELDS:
+ args.append(getattr(self, f))
buf = bytearray()
- msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.value)
+ msg_pack_into(self._VALUE_PACK_STR, buf, 0, *args)
return buf
@@ -618,6 +635,166 @@ class BGPPathAttributeCommunities(_PathAttribute):
return buf
+# Extended Communities
+# RFC 4360
+# RFC 5668
+# IANA registry:
+# https://www.iana.org/assignments/bgp-extended-communities/
+# bgp-extended-communities.xml
+#
+# type
+# high low
+# 00 sub-type Two-Octet AS Specific Extended Community (transitive)
+# 40 sub-type Two-Octet AS Specific Extended Community
+# payload:
+# 2 byte Global Administrator (AS number)
+# 4 byte Local Administrator (defined by sub-type)
+# 01 sub-type IPv4 Address Specific Extended Community (transitive)
+# 41 sub-type IPv4 Address Specific Extended Community
+# payload:
+# 4 byte Global Administrator (IPv4 address)
+# 2 byte Local Administrator (defined by sub-type)
+# 03 sub-type Opaque Extended Community (transitive)
+# 43 sub-type Opaque Extended Community
+# payload:
+# 6 byte opaque value (defined by sub-type)
+#
+# 00 02 Route Target Community (two-octet AS specific)
+# 01 02 Route Target Community (IPv4 address specific)
+# 02 02 Route Target Community (four-octet AS specific, RFC 5668)
+# 00 03 Route Origin Community (two-octet AS specific)
+# 01 03 Route Origin Community (IPv4 address specific)
+# 02 03 Route Origin Community (four-octet AS specific, RFC 5668)
+@_PathAttribute.register_type(BGP_ATTR_TYPE_EXTENDED_COMMUNITIES)
+class BGPPathAttributeExtendedCommunities(_PathAttribute):
+ _ATTR_FLAGS = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANSITIVE
+
+ def __init__(self, communities,
+ flags=0, type_=None, length=None):
+ super(BGPPathAttributeExtendedCommunities,
+ self).__init__(flags=flags,
+ type_=type_,
+ length=length)
+ self.communities = communities
+
+ @classmethod
+ def parse_value(cls, buf):
+ rest = buf
+ communities = []
+ while rest:
+ comm, rest = _ExtendedCommunity.parse(rest)
+ communities.append(comm)
+ return {
+ 'communities': communities,
+ }
+
+ def serialize_value(self):
+ buf = bytearray()
+ for comm in self.communities:
+ buf += comm.serialize()
+ return buf
+
+
+class _ExtendedCommunity(StringifyMixin, _TypeDisp, _Value):
+ _PACK_STR = '!B7s' # type high (+ type low) + value
+ IANA_AUTHORITY = 0x80
+ TRANSITIVE = 0x40
+ _TYPE_HIGH_MASK = ~TRANSITIVE
+
+ TWO_OCTET_AS_SPECIFIC = 0x00
+ IPV4_ADDRESS_SPECIFIC = 0x01
+ FOUR_OCTET_AS_SPECIFIC = 0x02
+ OPAQUE = 0x03
+
+ def __init__(self, type_):
+ self.type = type_
+
+ @classmethod
+ def parse(cls, buf):
+ (type_high, payload) = struct.unpack_from(cls._PACK_STR, buffer(buf))
+ rest = buf[struct.calcsize(cls._PACK_STR):]
+ type_ = type_high & cls._TYPE_HIGH_MASK
+ subcls = cls._lookup_type(type_)
+ return subcls(type_=type_high,
+ **subcls.parse_value(payload)), rest
+
+ def serialize(self):
+ buf = bytearray()
+ msg_pack_into(self._PACK_STR, buf, 0, self.type,
+ bytes(self.serialize_value()))
+ return buf
+
+
+@_ExtendedCommunity.register_type(_ExtendedCommunity.TWO_OCTET_AS_SPECIFIC)
+class BGPTwoOctetAsSpecificExtendedCommunity(_ExtendedCommunity):
+ _VALUE_PACK_STR = '!BHI' # sub type, as number, local adm
+ _VALUE_FIELDS = ['subtype', 'as_number', 'local_administrator']
+
+ def __init__(self, type_=_ExtendedCommunity.TWO_OCTET_AS_SPECIFIC,
+ **kwargs):
+ self.do_init(BGPTwoOctetAsSpecificExtendedCommunity, self, kwargs,
+ type_=type_)
+
+
+@_ExtendedCommunity.register_type(_ExtendedCommunity.IPV4_ADDRESS_SPECIFIC)
+class BGPIPv4AddressSpecificExtendedCommunity(_ExtendedCommunity):
+ _VALUE_PACK_STR = '!B4sH' # sub type, IPv4 address, local adm
+ _VALUE_FIELDS = ['subtype', 'ipv4_address', 'local_administrator']
+
+ def __init__(self, type_=_ExtendedCommunity.IPV4_ADDRESS_SPECIFIC,
+ **kwargs):
+ self.do_init(BGPIPv4AddressSpecificExtendedCommunity, self, kwargs,
+ type_=type_)
+
+ @classmethod
+ def parse_value(cls, buf):
+ d_ = super(BGPIPv4AddressSpecificExtendedCommunity,
+ cls).parse_value(buf)
+ d_['ipv4_address'] = addrconv.ipv4.bin_to_text(d_['ipv4_address'])
+ return d_
+
+ def serialize_value(self):
+ args = []
+ for f in self._VALUE_FIELDS:
+ v = getattr(self, f)
+ if f == 'ipv4_address':
+ v = bytes(addrconv.ipv4.text_to_bin(v))
+ args.append(v)
+ buf = bytearray()
+ msg_pack_into(self._VALUE_PACK_STR, buf, 0, *args)
+ return buf
+
+
+@_ExtendedCommunity.register_type(_ExtendedCommunity.FOUR_OCTET_AS_SPECIFIC)
+class BGPFourOctetAsSpecificExtendedCommunity(_ExtendedCommunity):
+ _VALUE_PACK_STR = '!BIH' # sub type, as number, local adm
+ _VALUE_FIELDS = ['subtype', 'as_number', 'local_administrator']
+
+ def __init__(self, type_=_ExtendedCommunity.FOUR_OCTET_AS_SPECIFIC,
+ **kwargs):
+ self.do_init(BGPFourOctetAsSpecificExtendedCommunity, self, kwargs,
+ type_=type_)
+
+
+@_ExtendedCommunity.register_type(_ExtendedCommunity.OPAQUE)
+class BGPOpaqueExtendedCommunity(_ExtendedCommunity):
+ _VALUE_PACK_STR = '!7s' # opaque value
+ _VALUE_FIELDS = ['opaque']
+
+ def __init__(self, type_=_ExtendedCommunity.OPAQUE,
+ **kwargs):
+ self.do_init(BGPOpaqueExtendedCommunity, self, kwargs,
+ type_=type_)
+
+
+@_ExtendedCommunity.register_unknown_type()
+class BGPUnknownExtendedCommunity(_ExtendedCommunity):
+ _VALUE_PACK_STR = '!7s' # opaque value
+
+ def __init__(self, **kwargs):
+ self.do_init(BGPUnknownExtendedCommunity, self, kwargs)
+
+
@_PathAttribute.register_type(BGP_ATTR_TYPE_MP_REACH_NLRI)
class BGPPathAttributeMpReachNLRI(_PathAttribute):
_VALUE_PACK_STR = '!HBB' # afi, safi, next hop len