Signed-off-by: ISHIDA Wataru <[email protected]>
---
 ryu/lib/packet/bgp/__init__.py |  146 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 139 insertions(+), 7 deletions(-)

diff --git a/ryu/lib/packet/bgp/__init__.py b/ryu/lib/packet/bgp/__init__.py
index 2d71917..50c9571 100644
--- a/ryu/lib/packet/bgp/__init__.py
+++ b/ryu/lib/packet/bgp/__init__.py
@@ -28,12 +28,12 @@ import struct
 
 from ryu.ofproto.ofproto_parser import msg_pack_into
 from ryu.lib.stringify import StringifyMixin
+from ryu.lib.packet import afi
+from ryu.lib.packet import safi
 from ryu.lib.packet import packet_base
 from ryu.lib.packet import stream_parser
 from ryu.lib import addrconv
 
-import safi
-import afi
 
 
 BGP_MSG_OPEN = 1
@@ -132,6 +132,20 @@ BGP_COMMUNITY_NO_EXPORT_SUBCONFED = 0xffffff03
 BGP_EXTENDED_COMMUNITY_ROUTE_TARGET = 0x02
 BGP_EXTENDED_COMMUNITY_ROUTE_ORIGIN = 0x03
 
+class RouteFamily(StringifyMixin):
+    def __init__(self, afi, safi):
+        self.afi = afi
+        self.safi = safi
+
+    def __cmp__(self, other):
+        return cmp((other.afi, other.safi), (self.afi, self.safi))
+
+# Route Family Singleton
+RF_IPv4_UC = RouteFamily(afi.IP, safi.UNICAST)
+RF_IPv6_UC = RouteFamily(afi.IP6, safi.UNICAST)
+RF_IPv4_VPN = RouteFamily(afi.IP, safi.MPLS_VPN)
+RF_IPv6_VPN = RouteFamily(afi.IP6, safi.MPLS_VPN) 
+RF_RTC_UC = RouteFamily(afi.IP, safi.ROUTE_TARGET_CONSTRTAINS)
 
 def pad(bin, len_):
     assert len(bin) <= len_
@@ -287,6 +301,22 @@ class _IPAddrPrefix(_AddrPrefix):
     def _prefix_from_bin(addr):
         return (addrconv.ipv4.bin_to_text(pad(addr, 4)),)
 
+class _IP6AddrPrefix(_AddrPrefix):
+    _TYPE = {
+        'ascii': [
+            'addr'
+        ]
+    }
+
+    @staticmethod
+    def _prefix_to_bin(addr):
+        (addr,) = addr
+        return addrconv.ipv6.text_to_bin(addr)
+
+    @staticmethod
+    def _prefix_from_bin(addr):
+        return (addrconv.ipv6.bin_to_text(pad(addr, 16)),)
+
 
 class _VPNAddrPrefix(_AddrPrefix):
     _RD_PACK_STR = '!Q'
@@ -320,19 +350,121 @@ class _VPNAddrPrefix(_AddrPrefix):
         (rd,) = struct.unpack_from(cls._RD_PACK_STR, buffer(binrd))
         return (rd,) + super(_VPNAddrPrefix, cls)._prefix_from_bin(binrest)
 
+class IPAddrPrefix(_UnlabelledAddrPrefix, _IPAddrPrefix):
+    ROUTE_FAMILY = RF_IPv4_UC
+
+    @property
+    def prefix(self):
+        return self.addr
+
+class IP6AddrPrefix(_UnlabelledAddrPrefix, _IP6AddrPrefix):
+    ROUTE_FAMILY = RF_IPv6_UC
+
+    @property
+    def prefix(self):
+        return self.addr
 
 class LabelledVPNIPAddrPrefix(_LabelledAddrPrefix, _VPNAddrPrefix,
                               _IPAddrPrefix):
-    pass
+    ROUTE_FAMILY = RF_IPv4_VPN
 
+class LabelledVPNIP6AddrPrefix(_LabelledAddrPrefix, _VPNAddrPrefix,
+                              _IP6AddrPrefix):
+    ROUTE_FAMILY = RF_IPv6_VPN
 
-class IPAddrPrefix(_UnlabelledAddrPrefix, _IPAddrPrefix):
-    pass
+class RouteTargetMembershipNLRI(StringifyMixin):
+    """Route Target Membership NLRI.
+
+    Route Target membership NLRI is advertised in BGP UPDATE messages using
+    the MP_REACH_NLRI and MP_UNREACH_NLRI attributes.
+    """
+ 
+    ROUTE_FAMILY = RF_RTC_UC
+    DEFAULT_AS = '0:0'
+    DEFAULT_RT = '0:0'
+
+    def __init__(self, origin_as, route_target):
+        # If given is not default_as and default_rt
+        if not (origin_as is RtNlri.DEFAULT_AS and
+                route_target is RtNlri.DEFAULT_RT):
+            # We validate them
+            if (not is_valid_old_asn(origin_as) or
+                    not is_valid_ext_comm_attr(route_target)):
+                raise ValueError('Invalid params.')
+        self.origin_as = origin_as
+        self.route_target = route_target
+
+    @property
+    def formatted_nlri_str(self):
+        return "%s:%s" % (self.origin_as, self.route_target)
+
+    def is_default_rtnlri(self):
+        if (self._origin_as is RtNlri.DEFAULT_AS and
+                self._route_target is RtNlri.DEFAULT_RT):
+            return True
+        return False
+
+    def __cmp__(self, other):
+        return cmp(
+            (self._origin_as, self._route_target),
+            (other.origin_as, other.route_target),
+        )
+
+    @classmethod
+    def parser(cls, buf):
+        idx = 0
+
+        # Extract origin AS.
+        origin_as, = struct.unpack_from('!I', buf, idx)
+        idx += 4
+
+        # Extract route target.
+        route_target = ''
+        etype, esubtype, payload = struct.unpack_from('BB6s', buf, idx)
+        # RFC says: The value of the high-order octet of the Type field for the
+        # Route Target Community can be 0x00, 0x01, or 0x02.  The value of the
+        # low-order octet of the Type field for this community is 0x02.
+        # TODO(PH): Remove this exception when it breaks something Here we make
+        # exception as Routem packs lower-order octet as 0x00
+        if etype in (0, 2) and esubtype in (0, 2):
+            # If we have route target community in AS number format.
+            asnum, i = struct.unpack('!HI', payload)
+            route_target = ('%s:%s' % (asnum, i))
+        elif etype == 1 and esubtype == 2:
+            # If we have route target community in IP address format.
+            ip_addr, i = struct.unpack('!4sH', payload)
+            ip_addr = socket.inet_ntoa(ip_addr)
+            route_target = ('%s:%s' % (ip_addr, i))
+        elif etype == 0 and esubtype == 1:
+            # TODO(PH): Parsing of RtNlri 1:1:100:1
+            asnum, i = struct.unpack('!HI', payload)
+            route_target = ('%s:%s' % (asnum, i))
+
+        return cls(origin_as, route_target)
+
+    def serialize(self):
+        rt_nlri = ''
+        if not self.is_default_rtnlri():
+            rt_nlri += struct.pack('!I', self.origin_as)
+            # Encode route target
+            first, second = self.route_target.split(':')
+            if '.' in first:
+                ip_addr = socket.inet_aton(first)
+                rt_nlri += struct.pack('!BB4sH', 1, 2, ip_addr, int(second))
+            else:
+                rt_nlri += struct.pack('!BBHI', 0, 2, int(first), int(second))
+
+        # RT Nlri is 12 octets
+        return struct.pack('B', (8 * 12)) + rt_nlri
 
+_addr_class_key = lambda x : (x.afi, x.safi)
 
 _ADDR_CLASSES = {
-    (afi.IP, safi.UNICAST): IPAddrPrefix,
-    (afi.IP, safi.MPLS_VPN): LabelledVPNIPAddrPrefix,
+    _addr_class_key(RF_IPv4_UC) : IPAddrPrefix,
+    _addr_class_key(RF_IPv6_UC) : IP6AddrPrefix,
+    _addr_class_key(RF_IPv4_VPN) : LabelledVPNIPAddrPrefix,
+    _addr_class_key(RF_IPv6_VPN) : LabelledVPNIP6AddrPrefix,
+    _addr_class_key(RF_RTC_UC) : RouteTargetMembershipNLRI,
 }
 
 
-- 
1.7.9.5


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/NeoTech
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to