From e9c8d4e6ad12560808547a42073faf654e7c4d1d Mon Sep 17 00:00:00 2001 From: Thomas Mangin Date: Mon, 21 Oct 2019 21:25:31 +0100 Subject: [PATCH] attempt to help with #927 and add support for RFC 5701 (no test code included) --- .../attribute/community/extended/__init__.py | 1 + .../attribute/community/extended/community.py | 6 ++-- .../attribute/community/extended/traffic.py | 28 +++++++++++++++++-- lib/exabgp/configuration/flow/parser.py | 12 ++++++-- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/exabgp/bgp/message/update/attribute/community/extended/__init__.py b/lib/exabgp/bgp/message/update/attribute/community/extended/__init__.py index 2f57db997..e0d1e02de 100644 --- a/lib/exabgp/bgp/message/update/attribute/community/extended/__init__.py +++ b/lib/exabgp/bgp/message/update/attribute/community/extended/__init__.py @@ -29,6 +29,7 @@ from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficRedirect from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficRedirectASN4 from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficMark +from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficRedirectIPv6 from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficNextHopIPv4IETF from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficNextHopIPv6IETF from exabgp.bgp.message.update.attribute.community.extended.traffic import TrafficNextHopSimpson diff --git a/lib/exabgp/bgp/message/update/attribute/community/extended/community.py b/lib/exabgp/bgp/message/update/attribute/community/extended/community.py index 8b6f2e450..d6cbf537e 100644 --- a/lib/exabgp/bgp/message/update/attribute/community/extended/community.py +++ b/lib/exabgp/bgp/message/update/attribute/community/extended/community.py @@ -21,8 +21,6 @@ class ExtendedCommunityBase (Attribute): COMMUNITY_SUBTYPE = 0x00 # MUST be redefined by subclasses NON_TRANSITIVE = 0x40 - registered_extended = {} - @classmethod def register (cls, klass): cls.registered_extended[(klass.COMMUNITY_TYPE & 0x0F,klass.COMMUNITY_SUBTYPE)] = klass @@ -117,6 +115,8 @@ class ExtendedCommunity (ExtendedCommunityBase): ID = Attribute.CODE.EXTENDED_COMMUNITY FLAG = Attribute.Flag.TRANSITIVE | Attribute.Flag.OPTIONAL + registered_extended = {} + def __len__ (self): return 8 @@ -125,5 +125,7 @@ class ExtendedCommunityIPv6 (ExtendedCommunityBase): ID = Attribute.CODE.IPV6_EXTENDED_COMMUNITY FLAG = Attribute.Flag.TRANSITIVE | Attribute.Flag.OPTIONAL + registered_extended = {} + def __len__ (self): return 20 diff --git a/lib/exabgp/bgp/message/update/attribute/community/extended/traffic.py b/lib/exabgp/bgp/message/update/attribute/community/extended/traffic.py index 959103d19..4186f41f5 100644 --- a/lib/exabgp/bgp/message/update/attribute/community/extended/traffic.py +++ b/lib/exabgp/bgp/message/update/attribute/community/extended/traffic.py @@ -7,6 +7,8 @@ License: 3-clause BSD. (See the COPYRIGHT file) """ +import socket + from struct import pack from struct import unpack @@ -221,8 +223,8 @@ def unpack (data): # draft-ietf-idr-flowspec-redirect-02 # see RFC 5701 for ipv6 address specific extended community format -@ExtendedCommunity.register -class TrafficNextHopIPv6IETF (ExtendedCommunityIPv6): +@ExtendedCommunityIPv6.register +class TrafficNextHopIPv6IETF ( ExtendedCommunityIPv6): COMMUNITY_TYPE = 0x00 COMMUNITY_SUBTYPE = 0x0C @@ -280,6 +282,28 @@ def unpack (data): bit, = unpack('!B',data[7:8]) return TrafficNextHopSimpson(bool(bit & 0x01), data[:8]) +# ============================================================ TrafficRedirectIPv6 +# https://tools.ietf.org/html/rfc5701 + +@ExtendedCommunityIPv6.register +class TrafficRedirectIPv6 (ExtendedCommunityIPv6): + COMMUNITY_TYPE = 0x00 + COMMUNITY_SUBTYPE = 0x02 + + def __init__(self, ip, asn, community=None): + self.ip = ip + self.asn = asn + ExtendedCommunityIPv6.__init__(self, community if community is not None else pack( + "!BB16sH", 0x00, 0x02, socket.inet_aton(socket.AF_INET6, ip), asn)) + + def __str__(self): + return "redirect %s:%d" % (self.ip, self.asn) + + @staticmethod + def unpack(data): + ip, asn = unpack('!16sH', data[2:11]) + return TrafficRedirectIPv6(socket.inet_ntoa(socket.AF_INET6, ip), asn, data[:11]) + # ============================================================ TrafficRedirectIP # RFC 5575 diff --git a/lib/exabgp/configuration/flow/parser.py b/lib/exabgp/configuration/flow/parser.py index 8ff7c7f07..15b6443c1 100644 --- a/lib/exabgp/configuration/flow/parser.py +++ b/lib/exabgp/configuration/flow/parser.py @@ -37,6 +37,7 @@ from exabgp.bgp.message.update.attribute.community.extended import TrafficRedirect from exabgp.bgp.message.update.attribute.community.extended import TrafficRedirectASN4 from exabgp.bgp.message.update.attribute.community.extended import TrafficMark +from exabgp.bgp.message.update.attribute.community.extended import TrafficRedirectIPv6 from exabgp.bgp.message.update.attribute.community.extended import TrafficNextHopIPv4IETF from exabgp.bgp.message.update.attribute.community.extended import TrafficNextHopIPv6IETF from exabgp.bgp.message.update.attribute.community.extended import TrafficNextHopSimpson @@ -275,7 +276,10 @@ def rate_limit (tokeniser): def redirect (tokeniser): data = tokeniser() - if data.count(':') == 1: + 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') @@ -293,8 +297,10 @@ def redirect (tokeniser): 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(TrafficNextHopSimpson(False)) - + elements = data.split(':') + ip = ':'.join(elements[:-1]) + asn = int(elements[-1]) + return IP.create(ip), ExtendedCommunities().add(TrafficRedirectIPv6(ip,asn)) def redirect_next_hop (tokeniser): return ExtendedCommunities().add(TrafficNextHopSimpson(False))