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

diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index 1ffd035..eb3e2d1 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -28,6 +28,7 @@ RFC 4271 BGP-4
 # - RFC 4486 Subcodes for BGP Cease Notification Message
 # - RFC 4760 Multiprotocol Extensions for BGP-4
 
+import abc
 import struct
 
 from ryu.ofproto.ofproto_parser import msg_pack_into
@@ -85,39 +86,70 @@ def pad(bin, len_):
     return bin + (len_ - len(bin)) * '\0'
 
 
-class _IPAddrPrefix(StringifyMixin):
+class _AddrPrefix(StringifyMixin):
+    __metaclass__ = abc.ABCMeta
     _PACK_STR = '!B'  # length
 
-    def __init__(self, length, ip_addr):
+    def __init__(self, length, addr):
         self.length = length
-        self.ip_addr = ip_addr
+        self.addr = addr
+
+    @staticmethod
+    @abc.abstractmethod
+    def _to_bin(addr):
+        return addr
+
+    @staticmethod
+    @abc.abstractmethod
+    def _to_text(addr):
+        return addr
 
     @classmethod
     def parser(cls, buf):
         (length, ) = struct.unpack_from(cls._PACK_STR, buffer(buf))
         rest = buf[struct.calcsize(cls._PACK_STR):]
         byte_length = (length + 7) / 8
-        ip_addr = addrconv.ipv4.bin_to_text(pad(rest[:byte_length], 4))
+        addr = cls._to_text(rest[:byte_length])
         rest = rest[byte_length:]
-        return cls(length=length, ip_addr=ip_addr), rest
+        return cls(length=length, addr=addr), rest
 
     def serialize(self):
         # fixup
         byte_length = (self.length + 7) / 8
-        bin_ip_addr = addrconv.ipv4.text_to_bin(self.ip_addr)
+        bin_addr = self._to_bin(self.addr)
         if (self.length % 8) == 0:
-            bin_ip_addr = bin_ip_addr[:byte_length]
+            bin_addr = bin_addr[:byte_length]
         else:
             # clear trailing bits in the last octet.
             # rfc doesn't require this.
             mask = 0xff00 >> (self.length % 8)
-            last_byte = chr(ord(bin_ip_addr[byte_length - 1]) & mask)
-            bin_ip_addr = bin_ip_addr[:byte_length - 1] + last_byte
-        self.ip_addr = addrconv.ipv4.bin_to_text(pad(bin_ip_addr, 4))
+            last_byte = chr(ord(bin_addr[byte_length - 1]) & mask)
+            bin_addr = bin_addr[:byte_length - 1] + last_byte
+        self.addr = self._to_text(bin_addr)
 
         buf = bytearray()
         msg_pack_into(self._PACK_STR, buf, 0, self.length)
-        return buf + bytes(bin_ip_addr)
+        return buf + bytes(bin_addr)
+
+
+class _BinAddrPrefix(_AddrPrefix):
+    @staticmethod
+    def _to_bin(addr):
+        return addr
+
+    @staticmethod
+    def _to_text(addr):
+        return addr
+
+
+class _IPAddrPrefix(_AddrPrefix):
+    @staticmethod
+    def _to_bin(addr):
+        return addrconv.ipv4.text_to_bin(addr)
+
+    @staticmethod
+    def _to_text(addr):
+        return addrconv.ipv4.bin_to_text(pad(addr, 4))
 
 
 class _Value(object):
@@ -484,26 +516,26 @@ class _BGPPathAttributeAggregatorCommon(_PathAttribute):
     _VALUE_PACK_STR = None
     _ATTR_FLAGS = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANSITIVE
 
-    def __init__(self, as_number, ip_addr, flags=0, type_=None, length=None):
+    def __init__(self, as_number, addr, flags=0, type_=None, length=None):
         super(_BGPPathAttributeAggregatorCommon, self).__init__(flags=flags,
                                                                 type_=type_,
                                                                 length=length)
         self.as_number = as_number
-        self.ip_addr = ip_addr
+        self.addr = addr
 
     @classmethod
     def parse_value(cls, buf):
-        (as_number, ip_addr) = struct.unpack_from(cls._VALUE_PACK_STR,
-                                                  buffer(buf))
+        (as_number, addr) = struct.unpack_from(cls._VALUE_PACK_STR,
+                                               buffer(buf))
         return {
             'as_number': as_number,
-            'ip_addr': addrconv.ipv4.bin_to_text(ip_addr),
+            'addr': addrconv.ipv4.bin_to_text(addr),
         }
 
     def serialize_value(self):
         buf = bytearray()
         msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.as_number,
-                      addrconv.ipv4.text_to_bin(self.ip_addr))
+                      addrconv.ipv4.text_to_bin(self.addr))
         return buf
 
 
@@ -518,6 +550,63 @@ class 
BGPPathAttributeAs4Aggregator(_BGPPathAttributeAggregatorCommon):
     _VALUE_PACK_STR = '!I4s'
 
 
+@_PathAttribute.register_type(BGP_ATTR_TYPE_MP_REACH_NLRI)
+class BGPPathAttributeMpReachNLRI(_PathAttribute):
+    _VALUE_PACK_STR = '!HBB'  # afi, safi, next hop len
+    _ATTR_FLAGS = BGP_ATTR_FLAG_OPTIONAL
+
+    def __init__(self, afi, safi, next_hop, nlri,
+                 next_hop_len=0, reserved='\0',
+                 flags=0, type_=None, length=None):
+        super(BGPPathAttributeMpReachNLRI, self).__init__(flags=flags,
+                                                          type_=type_,
+                                                          length=length)
+        self.afi = afi
+        self.safi = safi
+        self.next_hop_len = next_hop_len
+        self.next_hop = next_hop
+        self.reserved = reserved
+        self.nlri = nlri
+
+    @classmethod
+    def parse_value(cls, buf):
+        (afi, safi, next_hop_len,) = struct.unpack_from(cls._VALUE_PACK_STR,
+                                                        buffer(buf))
+        rest = buf[struct.calcsize(cls._VALUE_PACK_STR):]
+        next_hop_bin = rest[:next_hop_len]
+        rest = rest[next_hop_len:]
+        reserved = rest[:1]
+        binnlri = rest[1:]
+        nlri = []
+        while binnlri:
+            n, binnlri = _BinAddrPrefix.parser(binnlri)
+            nlri.append(n)
+        return {
+            'afi': afi,
+            'safi': safi,
+            'next_hop_len': next_hop_len,
+            'next_hop': next_hop_bin,
+            'reserved': reserved,
+            'nlri': nlri,
+        }
+
+    def serialize_value(self):
+        # fixup
+        self.next_hop_len = len(self.next_hop)
+        self.reserved = '\0'
+
+        buf = bytearray()
+        msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.afi,
+                      self.safi, self.next_hop_len)
+        buf += self.next_hop
+        buf += self.reserved
+        binnlri = bytearray()
+        for n in self.nlri:
+            binnlri += n.serialize()
+        buf += binnlri
+        return buf
+
+
 class BGPNLRI(_IPAddrPrefix):
     pass
 
diff --git a/ryu/tests/unit/packet/test_bgp.py 
b/ryu/tests/unit/packet/test_bgp.py
index 2e1da86..0dc7fb6 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -66,15 +66,19 @@ class Test_bgp(unittest.TestCase):
 
     def test_update2(self):
         withdrawn_routes = [bgp.BGPWithdrawnRoute(length=0,
-                                                  ip_addr='192.0.2.13'),
+                                                  addr='192.0.2.13'),
                             bgp.BGPWithdrawnRoute(length=1,
-                                                  ip_addr='192.0.2.13'),
+                                                  addr='192.0.2.13'),
                             bgp.BGPWithdrawnRoute(length=3,
-                                                  ip_addr='192.0.2.13'),
+                                                  addr='192.0.2.13'),
                             bgp.BGPWithdrawnRoute(length=7,
-                                                  ip_addr='192.0.2.13'),
+                                                  addr='192.0.2.13'),
                             bgp.BGPWithdrawnRoute(length=32,
-                                                  ip_addr='192.0.2.13')]
+                                                  addr='192.0.2.13')]
+        mp_nlri = [
+            bgp._BinAddrPrefix(32, 'efgh\0\0'),
+            bgp._BinAddrPrefix(16, 'ij\0\0\0\0'),
+        ]
         path_attributes = [
             bgp.BGPPathAttributeOrigin(value=1),
             bgp.BGPPathAttributeAsPath(value=[[1000], set([1001, 1002]),
@@ -84,16 +88,19 @@ class Test_bgp(unittest.TestCase):
             bgp.BGPPathAttributeLocalPref(value=1000000000),
             bgp.BGPPathAttributeAtomicAggregate(),
             bgp.BGPPathAttributeAggregator(as_number=40000,
-                                           ip_addr='192.0.2.99'),
+                                           addr='192.0.2.99'),
             bgp.BGPPathAttributeAs4Path(value=[[1000000], set([1000001, 1002]),
                                                [1003, 1000004]]),
             bgp.BGPPathAttributeAs4Aggregator(as_number=100040000,
-                                              ip_addr='192.0.2.99'),
+                                              addr='192.0.2.99'),
+            bgp.BGPPathAttributeMpReachNLRI(afi=afi.IP, safi=safi.MPLS_VPN,
+                                            next_hop='abcd',
+                                            nlri=mp_nlri),
             bgp.BGPPathAttributeUnknown(flags=0, type_=100, value=300*'bar')
         ]
         nlri = [
-            bgp.BGPNLRI(length=24, ip_addr='203.0.113.1'),
-            bgp.BGPNLRI(length=16, ip_addr='203.0.113.0')
+            bgp.BGPNLRI(length=24, addr='203.0.113.1'),
+            bgp.BGPNLRI(length=16, addr='203.0.113.0')
         ]
         msg = bgp.BGPUpdate(withdrawn_routes=withdrawn_routes,
                             path_attributes=path_attributes,
-- 
1.8.3.1


------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to