i misunderstood that RDs were in-core.
actually they are on-wire.

Signed-off-by: YAMAMOTO Takashi <[email protected]>
---
 ryu/lib/packet/bgp.py             | 91 ++++++++++++++++++++++++++++++---------
 ryu/tests/unit/packet/test_bgp.py | 16 +++++--
 2 files changed, 82 insertions(+), 25 deletions(-)

diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index ffd332a..6c1d6ad 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -141,8 +141,16 @@ class _AddrPrefix(StringifyMixin):
     __metaclass__ = abc.ABCMeta
     _PACK_STR = '!B'  # length
 
-    def __init__(self, length, addr):
+    def __init__(self, length, addr, prefixes=None):
+        # length is on-wire bit length of prefixes+addr.
+        assert prefixes != ()
+        if isinstance(addr, tuple):
+            # for _AddrPrefix.parser
+            # also for _VPNAddrPrefix.__init__ etc
+            (addr,) = addr
         self.length = length
+        if prefixes:
+            addr = prefixes + (addr,)
         self.addr = addr
 
     @staticmethod
@@ -196,19 +204,22 @@ class _BinAddrPrefix(_AddrPrefix):
 class _LabelledAddrPrefix(_AddrPrefix):
     _LABEL_PACK_STR = '!3B'
 
-    def __init__(self, length, addr, labels=[]):
+    def __init__(self, length, addr, labels=[], **kwargs):
         assert isinstance(labels, list)
-        if isinstance(addr, tuple):
+        is_tuple = isinstance(addr, tuple)
+        if is_tuple:
+            # for _AddrPrefix.parser
             assert not labels
-            our_addr = addr
-            our_length = length
+            labels = addr[0]
+            addr = addr[1:]
         else:
-            label_length = struct.calcsize(self._LABEL_PACK_STR) * 8 * \
-                len(labels)
-            our_length = label_length + length
-            our_addr = (labels, addr)
-        super(_LabelledAddrPrefix, self).__init__(length=our_length,
-                                                  addr=our_addr)
+            length += struct.calcsize(self._LABEL_PACK_STR) * 8 * len(labels)
+        assert length > struct.calcsize(self._LABEL_PACK_STR) * 8 * len(labels)
+        prefixes = (labels,)
+        super(_LabelledAddrPrefix, self).__init__(prefixes=prefixes,
+                                                  length=length,
+                                                  addr=addr,
+                                                  **kwargs)
 
     @classmethod
     def _label_to_bin(cls, label):
@@ -227,33 +238,36 @@ class _LabelledAddrPrefix(_AddrPrefix):
 
     @classmethod
     def _to_bin(cls, addr):
-        (labels, prefix) = addr
+        labels = addr[0]
+        rest = addr[1:]
         labels = map(lambda x: x << 4, labels)
         if labels:
             labels[-1] |= 1  # bottom of stack
         bin_labels = map(cls._label_to_bin, labels)
         return bytes(reduce(lambda x, y: x + y, bin_labels,
-                            bytearray()) + cls._prefix_to_bin(prefix))
+                            bytearray()) + cls._prefix_to_bin(rest))
 
     @classmethod
     def _from_bin(cls, addr):
+        rest = addr
         labels = []
         while True:
-            (label, addr) = cls._label_from_bin(addr)
+            (label, rest) = cls._label_from_bin(rest)
             labels.append(label >> 4)
             if label & 1:  # bottom of stack
                 break
-        return (labels, cls._prefix_from_bin(addr))
+        return (labels,) + cls._prefix_from_bin(rest)
 
 
 class _UnlabelledAddrPrefix(_AddrPrefix):
     @classmethod
     def _to_bin(cls, addr):
-        return cls._prefix_to_bin(addr)
+        return cls._prefix_to_bin((addr,))
 
     @classmethod
-    def _from_bin(cls, addr):
-        return cls._prefix_from_bin(addr)
+    def _from_bin(cls, binaddr):
+        (addr,) = cls._prefix_from_bin(binaddr)
+        return addr
 
 
 class _IPAddrPrefix(_AddrPrefix):
@@ -265,14 +279,49 @@ class _IPAddrPrefix(_AddrPrefix):
 
     @staticmethod
     def _prefix_to_bin(addr):
+        (addr,) = addr
         return addrconv.ipv4.text_to_bin(addr)
 
     @staticmethod
     def _prefix_from_bin(addr):
-        return addrconv.ipv4.bin_to_text(pad(addr, 4))
+        return (addrconv.ipv4.bin_to_text(pad(addr, 4)),)
+
+
+class _VPNAddrPrefix(_AddrPrefix):
+    _RD_PACK_STR = '!Q'
+
+    def __init__(self, length, addr, prefixes=(), route_dist=0):
+        if isinstance(addr, tuple):
+            # for _AddrPrefix.parser
+            assert not route_dist
+            assert length > struct.calcsize(self._RD_PACK_STR) * 8
+            route_dist = addr[0]
+            addr = addr[1:]
+        else:
+            length += struct.calcsize(self._RD_PACK_STR) * 8
+        prefixes = prefixes + (route_dist,)
+        super(_VPNAddrPrefix, self).__init__(prefixes=prefixes,
+                                             length=length,
+                                             addr=addr)
+
+    @classmethod
+    def _prefix_to_bin(cls, addr):
+        rd = addr[0]
+        rest = addr[1:]
+        binrd = bytearray()
+        msg_pack_into(cls._RD_PACK_STR, binrd, 0, rd)
+        return binrd + super(_VPNAddrPrefix, cls)._prefix_to_bin(rest)
+
+    @classmethod
+    def _prefix_from_bin(cls, binaddr):
+        binrd = binaddr[:8]
+        binrest = binaddr[8:]
+        (rd,) = struct.unpack_from(cls._RD_PACK_STR, buffer(binrd))
+        return (rd,) + super(_VPNAddrPrefix, cls)._prefix_from_bin(binrest)
 
 
-class LabelledIPAddrPrefix(_LabelledAddrPrefix, _IPAddrPrefix):
+class LabelledVPNIPAddrPrefix(_LabelledAddrPrefix, _VPNAddrPrefix,
+                              _IPAddrPrefix):
     pass
 
 
@@ -282,7 +331,7 @@ class IPAddrPrefix(_UnlabelledAddrPrefix, _IPAddrPrefix):
 
 _ADDR_CLASSES = {
     (afi.IP, safi.UNICAST): IPAddrPrefix,
-    (afi.IP, safi.MPLS_VPN): LabelledIPAddrPrefix,
+    (afi.IP, safi.MPLS_VPN): LabelledVPNIPAddrPrefix,
 }
 
 
diff --git a/ryu/tests/unit/packet/test_bgp.py 
b/ryu/tests/unit/packet/test_bgp.py
index deebb9a..6764da4 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -79,8 +79,12 @@ class Test_bgp(unittest.TestCase):
                             bgp.BGPWithdrawnRoute(length=32,
                                                   addr='192.0.2.13')]
         mp_nlri = [
-            bgp.LabelledIPAddrPrefix(24, '192.0.9.0', labels=[1, 2, 3]),
-            bgp.LabelledIPAddrPrefix(26, '192.0.10.192', labels=[5, 6, 7, 8]),
+            bgp.LabelledVPNIPAddrPrefix(24, '192.0.9.0',
+                                        route_dist=100,
+                                        labels=[1, 2, 3]),
+            bgp.LabelledVPNIPAddrPrefix(26, '192.0.10.192',
+                                        route_dist=4000000000,
+                                        labels=[5, 6, 7, 8]),
         ]
         communities = [
             bgp.BGP_COMMUNITY_NO_EXPORT,
@@ -224,8 +228,12 @@ class Test_bgp(unittest.TestCase):
                             bgp.BGPWithdrawnRoute(length=32,
                                                   addr='192.0.2.13')]
         mp_nlri = [
-            bgp.LabelledIPAddrPrefix(24, '192.0.9.0', labels=[1, 2, 3]),
-            bgp.LabelledIPAddrPrefix(26, '192.0.10.192', labels=[5, 6, 7, 8]),
+            bgp.LabelledVPNIPAddrPrefix(24, '192.0.9.0',
+                                        route_dist=100,
+                                        labels=[1, 2, 3]),
+            bgp.LabelledVPNIPAddrPrefix(26, '192.0.10.192',
+                                        route_dist=4000000000,
+                                        labels=[5, 6, 7, 8]),
         ]
         communities = [
             bgp.BGP_COMMUNITY_NO_EXPORT,
-- 
1.8.3.1


------------------------------------------------------------------------------
CenturyLink Cloud: The Leader in Enterprise Cloud Services.
Learn Why More Businesses Are Choosing CenturyLink Cloud For
Critical Workloads, Development Environments & Everything In Between.
Get a Quote or Start a Free Trial Today. 
http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to