Signed-off-by: Wataru ISHIDA <[email protected]>
---
 ryu/lib/packet/ipv4.py |   2 +
 ryu/lib/packet/ospf.py | 691 +++++++++++++++++++++++++++++++++++++++++++++++++
 ryu/ofproto/inet.py    |   1 +
 3 files changed, 694 insertions(+)
 create mode 100644 ryu/lib/packet/ospf.py

diff --git a/ryu/lib/packet/ipv4.py b/ryu/lib/packet/ipv4.py
index 2247bdb..c6dba6c 100644
--- a/ryu/lib/packet/ipv4.py
+++ b/ryu/lib/packet/ipv4.py
@@ -22,6 +22,7 @@ from . import igmp
 from . import udp
 from . import tcp
 from . import sctp
+from . import ospf
 from ryu.ofproto import inet
 from ryu.lib import addrconv
 
@@ -140,3 +141,4 @@ ipv4.register_packet_type(igmp.igmp, inet.IPPROTO_IGMP)
 ipv4.register_packet_type(tcp.tcp, inet.IPPROTO_TCP)
 ipv4.register_packet_type(udp.udp, inet.IPPROTO_UDP)
 ipv4.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
+ipv4.register_packet_type(ospf.ospf, inet.IPPROTO_OSPF)
diff --git a/ryu/lib/packet/ospf.py b/ryu/lib/packet/ospf.py
new file mode 100644
index 0000000..49a7a6a
--- /dev/null
+++ b/ryu/lib/packet/ospf.py
@@ -0,0 +1,691 @@
+"""
+RFC 2328 OSPF version 2
+"""
+
+import struct
+
+from ryu.lib.stringify import StringifyMixin
+from ryu.lib.packet import packet_base
+from ryu.lib.packet import packet_utils
+from ryu.lib.packet import stream_parser
+
+from ryu.lib import addrconv
+
+_VERSION = 2
+
+OSPF_MSG_UNKNOWN = 0
+OSPF_MSG_HELLO = 1
+OSPF_MSG_DB_DESC = 2
+OSPF_MSG_LS_REQ = 3
+OSPF_MSG_LS_UPD = 4
+OSPF_MSG_LS_ACK = 5
+
+OSPF_UNKNOWN_LSA = 0
+OSPF_ROUTER_LSA = 1
+OSPF_NETWORK_LSA = 2
+OSPF_SUMMARY_LSA = 3
+OSPF_ASBR_SUMMARY_LSA = 4
+OSPF_AS_EXTERNAL_LSA = 5
+OSPF_AS_NSSA_LSA = 7       # RFC 3101
+OSPF_OPAQUE_LINK_LSA = 9   # RFC 5250
+OSPF_OPAQUE_AREA_LSA = 10  # RFC 5250
+OSPF_OPAQUE_AS_LSA = 11    # RFC 5250
+
+OSPF_OPTION_T = 1        # Obsolete
+OSPF_OPTION_E = 1 << 1   # RFC 2328
+OSPF_OPTION_MC = 1 << 2  # RFC 1584
+OSPF_OPTION_NP = 1 << 3  # RFC 3101
+OSPF_OPTION_EA = 1 << 4  # Obsolete
+OSPF_OPTION_DC = 1 << 5  # RFC 2370
+OSPF_OPTION_DN = 1 << 7  # RFC 2567
+
+LSA_LINK_TYPE_P2P = 1
+LSA_LINK_TYPE_TRANSIT = 2
+LSA_LINK_TYPE_STUB = 3
+LSA_LINK_TYPE_VL = 4
+
+ROUTER_LSA_BORDER = 0x01  # The router is an ABR
+ROUTER_LSA_EXTERNAL = 0x02  # The router is an ASBR
+ROUTER_LSA_VIRTUAL = 0x04  # The router has a VL in this area
+ROUTER_LSA_NT = 0x10  # The router always translates Type-7
+ROUTER_LSA_SHORTCUT = 0x20  # Shortcut-ABR specific flag
+
+AS_EXTERNAL_METRIC = 0x80
+
+
+class InvalidChecksum(Exception):
+    pass
+
+
+class _TypeDisp(object):
+    _TYPES = {}
+    _REV_TYPES = None
+    _UNKNOWN_TYPE = None
+
+    @classmethod
+    def register_unknown_type(cls):
+        def _register_type(subcls):
+            cls._UNKNOWN_TYPE = subcls
+            return subcls
+        return _register_type
+
+    @classmethod
+    def register_type(cls, type_):
+        cls._TYPES = cls._TYPES.copy()
+
+        def _register_type(subcls):
+            cls._TYPES[type_] = subcls
+            cls._REV_TYPES = None
+            return subcls
+        return _register_type
+
+    @classmethod
+    def _lookup_type(cls, type_):
+        try:
+            return cls._TYPES[type_]
+        except KeyError:
+            return cls._UNKNOWN_TYPE
+
+    @classmethod
+    def _rev_lookup_type(cls, targ_cls):
+        if cls._REV_TYPES is None:
+            rev = dict((v, k) for k, v in cls._TYPES.iteritems())
+            cls._REV_TYPES = rev
+        return cls._REV_TYPES[targ_cls]
+
+
+class LSAHeader(StringifyMixin):
+    _HDR_PACK_STR = '!HBB4s4sIHH'
+    _HDR_LEN = struct.calcsize(_HDR_PACK_STR)
+
+    def __init__(self, ls_age=0, options=0, type_=OSPF_UNKNOWN_LSA,
+                 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
+                 checksum=None, length=None):
+        self.ls_age = ls_age
+        self.options = options
+        self.type_ = type_
+        self.id_ = id_
+        self.adv_router = adv_router
+        self.ls_seqnum = ls_seqnum
+        self.checksum = checksum
+        self.length = length
+
+    @classmethod
+    def parser(cls, buf):
+        if len(buf) < cls._HDR_LEN:
+            raise stream_parser.StreamParser.TooSmallException(
+                '%d < %d' % (len(buf), cls._HDR_LEN))
+        (ls_age, options, type_, id_, adv_router, ls_seqnum, checksum,
+         length,) = struct.unpack_from(cls._HDR_PACK_STR, buffer(buf))
+        id_ = addrconv.ipv4.bin_to_text(id_)
+        adv_router = addrconv.ipv4.bin_to_text(adv_router)
+        rest = buf[cls._HDR_LEN:]
+
+        return {
+            "ls_age": ls_age,
+            "options": options,
+            "type_": type_,
+            "id_": id_,
+            "adv_router": adv_router,
+            "ls_seqnum": ls_seqnum,
+            "checksum": checksum,
+            "length": length,
+            }, rest
+
+    def serialize(self):
+        id_ = addrconv.ipv4.text_to_bin(self.id_)
+        adv_router = addrconv.ipv4.text_to_bin(self.adv_router)
+        return bytearray(struct.pack(self._HDR_PACK_STR, self.ls_age,
+                         self.options, self.type_, id_, adv_router,
+                         self.ls_seqnum, self.checksum, self.length))
+
+
+class LSA(_TypeDisp, StringifyMixin):
+    def __init__(self, ls_age=0, options=0, type_=OSPF_UNKNOWN_LSA,
+                 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
+                 checksum=None, length=None):
+        self.header = LSAHeader(ls_age, options, type_, id_, adv_router,
+                                ls_seqnum, 0, 0)
+        if not (checksum or length):
+            tail = self.serialize_tail()
+            length = self.header._HDR_LEN + len(tail)
+        if not checksum:
+            head = self.header.serialize()
+            checksum = packet_utils.fletcher_checksum(head[2:], 14)
+        self.header.length = length
+        self.header.checksum = checksum
+
+    @classmethod
+    def parser(cls, buf):
+        hdr, rest = LSAHeader.parser(buf)
+        #exclude ls_age for checksum calculation
+        csum = packet_utils.fletcher_checksum(buf[2:hdr['length']], 14)
+        if csum != hdr['checksum']:
+            raise InvalidChecksum("header has %d, but calculated value is %d"
+                                  % (hdr['checksum'], csum))
+        subcls = cls._lookup_type(hdr['type_'])
+        body = rest[:hdr['length']-LSAHeader._HDR_LEN]
+        rest = rest[hdr['length']-LSAHeader._HDR_LEN:]
+        kwargs = subcls.parser(body)
+        kwargs.update(hdr)
+        return subcls(**kwargs), subcls, rest
+
+    def serialize(self):
+        tail = self.serialize_tail()
+        self.header.length = self.header._HDR_LEN + len(tail)
+        head = self.header.serialize()
+        #exclude ls_age for checksum calculation
+        csum = packet_utils.fletcher_checksum(head[2:]+tail, 14)
+        self.header.checksum = csum
+        struct.pack_into("!H", head, 16, csum)
+        return head + tail
+
+
[email protected]_type(OSPF_ROUTER_LSA)
+class RouterLSA(LSA):
+    _PACK_STR = '!BBH'
+    _PACK_LEN = struct.calcsize(_PACK_STR)  # 4bytes
+
+    class Link(StringifyMixin):
+        _PACK_STR = '!4s4sBBH'
+        _PACK_LEN = struct.calcsize(_PACK_STR)  # 12bytes
+
+        def __init__(self, id_='0.0.0.0', data='0.0.0.0',
+                     type_=LSA_LINK_TYPE_STUB, tos=0, metric=10):
+            self.id_ = id_
+            self.data = data
+            self.type_ = type_
+            self.tos = tos
+            self.metric = metric
+
+        @classmethod
+        def parser(cls, buf):
+            if len(buf) < cls._PACK_LEN:
+                raise stream_parser.StreamParser.TooSmallException(
+                    '%d < %d' % (len(buf), cls._PACK_LEN))
+            link = buf[:cls._PACK_LEN]
+            rest = buf[cls._PACK_LEN:]
+            (id_, data, type_, tos, metric) = \
+                struct.unpack_from(cls._PACK_STR, buffer(link))
+            id_ = addrconv.ipv4.bin_to_text(id_)
+            data = addrconv.ipv4.bin_to_text(data)
+            return cls(id_, data, type_, tos, metric), rest
+
+        def serialize(self):
+            id_ = addrconv.ipv4.text_to_bin(self.id_)
+            data = addrconv.ipv4.text_to_bin(self.data)
+            return bytearray(struct.pack(self._PACK_STR, id_, data, self.type_,
+                             self.tos, self.metric))
+
+    def __init__(self, ls_age=0, options=0, type_=OSPF_ROUTER_LSA,
+                 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
+                 checksum=None, length=None, flags=0, links=[]):
+        self.flags = flags
+        self.links = links
+        super(RouterLSA, self).__init__(ls_age, options, type_, id_,
+                                        adv_router, ls_seqnum, checksum,
+                                        length)
+
+    @classmethod
+    def parser(cls, buf):
+        links = []
+        hdr = buf[:cls._PACK_LEN]
+        buf = buf[cls._PACK_LEN:]
+        (flags, padding, num) = struct.unpack_from(cls._PACK_STR, buffer(hdr))
+        while buf:
+            link, buf = cls.Link.parser(buf)
+            links.append(link)
+        assert(len(links) == num)
+        return {
+            "flags": flags,
+            "links": links,
+        }
+
+    def serialize_tail(self):
+        head = bytearray(struct.pack(self._PACK_STR, self.flags, 0,
+                         len(self.links)))
+        try:
+            return head + reduce(lambda a, b: a+b,
+                                 (link.serialize() for link in self.links))
+        except TypeError:
+            return head
+
+
[email protected]_type(OSPF_NETWORK_LSA)
+class NetworkLSA(LSA):
+    _PACK_STR = '!4s'
+    _PACK_LEN = struct.calcsize(_PACK_STR)
+
+    def __init__(self, ls_age=0, options=0, type_=OSPF_NETWORK_LSA,
+                 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
+                 checksum=None, length=None, mask='0.0.0.0', routers=[]):
+        self.mask = mask
+        self.routers = routers
+        super(NetworkLSA, self).__init__(ls_age, options, type_, id_,
+                                         adv_router, ls_seqnum, checksum,
+                                         length)
+
+    @classmethod
+    def parser(cls, buf):
+        if len(buf) < cls._PACK_LEN:
+            raise stream_parser.StreamParser.TooSmallException(
+                '%d < %d' % (len(buf), cls._PACK_LEN))
+        binmask = buf[:cls._PACK_LEN]
+        (mask,) = struct.unpack_from(cls._PACK_STR, buffer(binmask))
+        mask = addrconv.ipv4.bin_to_text(mask)
+        buf = buf[cls._PACK_LEN:]
+        routers = []
+        while buf:
+            binrouter = buf[:cls._PACK_LEN]
+            (router,) = struct.unpack_from(cls._PACK_STR, buffer(binrouter))
+            router = addrconv.ipv4.bin_to_text(router)
+            routers.append(router)
+            buf = buf[cls._PACK_LEN:]
+        return {
+            "mask": mask,
+            "routers": routers,
+        }
+
+    def serialize_tail(self):
+        mask = addrconv.ipv4.text_to_bin(self.mask)
+        routers = [addrconv.ipv4.text_to_bin(
+                   router) for router in self.routers]
+        return bytearray(struct.pack("!"+"4s"*(1+len(routers)), mask,
+                                     *routers))
+
+
[email protected]_type(OSPF_SUMMARY_LSA)
+class SummaryLSA(LSA):
+    pass
+
+
[email protected]_type(OSPF_ASBR_SUMMARY_LSA)
+class ASBRSummaryLSA(LSA):
+    pass
+
+
[email protected]_type(OSPF_AS_EXTERNAL_LSA)
+class ASExternalLSA(LSA):
+    class ExternalNetwork(StringifyMixin):
+        _PACK_STR = '!4sBBH4sI'
+        _PACK_LEN = struct.calcsize(_PACK_STR)
+
+        def __init__(self, mask='0.0.0.0', flags=0, metric=0,
+                     fwd_addr='0.0.0.0', tag=0):
+            self.mask = mask
+            self.flags = flags
+            self.metric = metric
+            self.fwd_addr = fwd_addr
+            self.tag = tag
+
+        @classmethod
+        def parser(cls, buf):
+            if len(buf) < cls._PACK_LEN:
+                raise stream_parser.StreamParser.TooSmallException(
+                    '%d < %d' % (len(buf), cls._PACK_LEN))
+            ext_nw = buf[:cls._PACK_LEN]
+            rest = buf[cls._PACK_LEN:]
+            (mask, flags, metric_fst, metric_lst, fwd_addr,
+             tag) = struct.unpack_from(cls._PACK_STR, buffer(ext_nw))
+            mask = addrconv.ipv4.bin_to_text(mask)
+            metric = metric_fst << 16 | (metric_lst & 0xffff)
+            fwd_addr = addrconv.ipv4.bin_to_text(fwd_addr)
+            return cls(mask, flags, metric, fwd_addr, tag), rest
+
+        def serialize(self):
+            mask = addrconv.ipv4.text_to_bin(self.mask)
+            metric_fst = (self.metric >> 16) & 0xff
+            metric_lst = self.metric & 0xffff
+            fwd_addr = addrconv.ipv4.text_to_bin(self.fwd_addr)
+            return bytearray(struct.pack(self._PACK_STR, mask, self.flags,
+                                         metric_fst, metric_lst, fwd_addr,
+                                         self.tag))
+
+    def __init__(self, ls_age=0, options=0, type_=OSPF_AS_EXTERNAL_LSA,
+                 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
+                 checksum=None, length=None, extnws=[]):
+        self.extnws = extnws
+        super(ASExternalLSA, self).__init__(ls_age, options, type_, id_,
+                                            adv_router, ls_seqnum, checksum,
+                                            length)
+
+    @classmethod
+    def parser(cls, buf):
+        extnws = []
+        while buf:
+            extnw, buf = cls.ExternalNetwork.parser(buf)
+            extnws.append(extnw)
+        return {
+            "extnws": extnws,
+        }
+
+    def serialize_tail(self):
+        return reduce(lambda a, b: a+b,
+                      (extnw.serialize() for extnw in self.extnws))
+
+
[email protected]_type(OSPF_AS_NSSA_LSA)
+class NSSAExternalLSA(LSA):
+    pass
+
+
[email protected]_type(OSPF_OPAQUE_LINK_LSA)
+class LocalOpaqueLSA(LSA):
+    pass
+
+
[email protected]_type(OSPF_OPAQUE_AREA_LSA)
+class AreaOpaqueLSA(LSA):
+    pass
+
+
[email protected]_type(OSPF_OPAQUE_AS_LSA)
+class ASOpaqueLSA(LSA):
+    pass
+
+
+class OSPFMessage(packet_base.PacketBase, _TypeDisp):
+    """Base class for OSPF version 2 messages.
+    """
+
+    _HDR_PACK_STR = '!BBH4s4sHHQ'
+    _HDR_LEN = struct.calcsize(_HDR_PACK_STR)
+
+    def __init__(self, type_, length=None, router_id='0.0.0.0',
+                 area_id='0.0.0.0', au_type=1, authentication=0, checksum=None,
+                 version=_VERSION):
+        self.version = version
+        self.type_ = type_
+        self.length = length
+        self.router_id = router_id
+        self.area_id = area_id
+        self.checksum = checksum
+        self.au_type = au_type
+        self.authentication = authentication
+
+    @classmethod
+    def parser(cls, buf):
+        if len(buf) < cls._HDR_LEN:
+            raise stream_parser.StreamParser.TooSmallException(
+                '%d < %d' % (len(buf), cls._HDR_LEN))
+        (version, type_, length, router_id, area_id, checksum, au_type,
+         authentication) = struct.unpack_from(cls._HDR_PACK_STR, buffer(buf))
+
+        #Exclude checksum and authentication field for checksum validation.
+        if packet_utils.checksum(buf[:12]+buf[14:16]+buf[cls._HDR_LEN:]) \
+                != checksum:
+            raise InvalidChecksum
+
+        if len(buf) < length:
+            raise stream_parser.StreamParser.TooSmallException(
+                '%d < %d' % (len(buf), length))
+
+        router_id = addrconv.ipv4.bin_to_text(router_id)
+        area_id = addrconv.ipv4.bin_to_text(area_id)
+        binmsg = buf[cls._HDR_LEN:length]
+        rest = buf[length:]
+        subcls = cls._lookup_type(type_)
+        kwargs = subcls.parser(binmsg)
+        return subcls(length, router_id, area_id, au_type, authentication,
+                      checksum, version, **kwargs), None, rest
+
+    def serialize(self):
+        tail = self.serialize_tail()
+        self.length = self._HDR_LEN + len(tail)
+        head = bytearray(struct.pack(self._HDR_PACK_STR, self.version,
+                         self.type_, self.length,
+                         addrconv.ipv4.text_to_bin(self.router_id),
+                         addrconv.ipv4.text_to_bin(self.area_id), 0,
+                         self.au_type, self.authentication))
+        buf = head + tail
+        csum = packet_utils.checksum(buf[:12]+buf[14:16]+buf[self._HDR_LEN:])
+        self.checksum = csum
+        struct.pack_into("!H", buf, 12, csum)
+        return buf
+
+#alias
+ospf = OSPFMessage
+
+
[email protected]_type(OSPF_MSG_HELLO)
+class OSPFHello(OSPFMessage):
+
+    _PACK_STR = '!4sHBBI4s4s'  # + neighbors
+    _PACK_LEN = struct.calcsize(_PACK_STR)
+    _MIN_LEN = OSPFMessage._HDR_LEN + _PACK_LEN
+
+    def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
+                 au_type=1, authentication=0, checksum=None, version=_VERSION,
+                 mask='0.0.0.0', hello_interval=10, options=0, priority=1,
+                 dead_interval=40, designated_router='0.0.0.0',
+                 backup_router='0.0.0.0', neighbors=[]):
+        super(OSPFHello, self).__init__(OSPF_MSG_HELLO, length, router_id,
+                                        area_id, au_type, authentication,
+                                        checksum, version)
+        self.mask = mask
+        self.hello_interval = hello_interval
+        self.options = options
+        self.priority = priority
+        self.dead_interval = dead_interval
+        self.designated_router = designated_router
+        self.backup_router = backup_router
+        self.neighbors = neighbors
+
+    @classmethod
+    def parser(cls, buf):
+        (mask, hello_interval, options, priority, dead_interval,
+         designated_router, backup_router) = struct.unpack_from(cls._PACK_STR,
+                                                                buffer(buf))
+        mask = addrconv.ipv4.bin_to_text(mask)
+        designated_router = addrconv.ipv4.bin_to_text(designated_router)
+        backup_router = addrconv.ipv4.bin_to_text(backup_router)
+        neighbors = []
+        binneighbors = buf[cls._PACK_LEN:len(buf)]
+        while binneighbors:
+            n = binneighbors[:4]
+            n = addrconv.ipv4.bin_to_text(n)
+            binneighbors = binneighbors[4:]
+            neighbors.append(n)
+        return {
+            "mask": mask,
+            "hello_interval": hello_interval,
+            "options": options,
+            "priority": priority,
+            "dead_interval": dead_interval,
+            "designated_router": designated_router,
+            "backup_router": backup_router,
+            "neighbors": neighbors,
+        }
+
+    def serialize_tail(self):
+        head = bytearray(struct.pack(self._PACK_STR,
+                         addrconv.ipv4.text_to_bin(self.mask),
+                         self.hello_interval, self.options, self.priority,
+                         self.dead_interval,
+                         addrconv.ipv4.text_to_bin(self.designated_router),
+                         addrconv.ipv4.text_to_bin(self.backup_router)))
+        try:
+            return head + reduce(lambda a, b: a+b,
+                                 (addrconv.ipv4.text_to_bin(
+                                  n) for n in self.neighbors))
+        except TypeError:
+            return head
+
+
[email protected]_type(OSPF_MSG_DB_DESC)
+class OSPFDBDesc(OSPFMessage):
+
+    _PACK_STR = '!HBBI'  # + LSA_HEADERS
+    _PACK_LEN = struct.calcsize(_PACK_STR)
+    _MIN_LEN = OSPFMessage._HDR_LEN + _PACK_LEN
+
+    def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
+                 au_type=1, authentication=0, checksum=None, version=_VERSION,
+                 mtu=1500, options=0, i_flag=0, m_flag=0, ms_flag=0,
+                 sequence_number=0, lsa_headers=[]):
+        super(OSPFDBDesc, self).__init__(OSPF_MSG_DB_DESC, length, router_id,
+                                         area_id, au_type, authentication,
+                                         checksum, version)
+        self.mtu = mtu
+        self.options = options
+        self.i_flag = i_flag
+        self.m_flag = m_flag
+        self.ms_flag = ms_flag
+        self.sequence_number = sequence_number
+        self.lsa_headers = lsa_headers
+
+    @classmethod
+    def parser(cls, buf):
+        (mtu, options, flags,
+         sequence_number) = struct.unpack_from(cls._PACK_STR, buffer(buf))
+        i_flag = (flags >> 2) & 0x1
+        m_flag = (flags >> 1) & 0x1
+        ms_flag = flags & 0x1
+        lsahdrs = []
+        buf = buf[cls._PACK_LEN:]
+        while buf:
+            kwargs, buf = LSAHeader.parser(buf)
+            lsahdrs.append(LSAHeader(**kwargs))
+        return {
+            "mtu": mtu,
+            "options": options,
+            "i_flag": i_flag,
+            "m_flag": m_flag,
+            "ms_flag": ms_flag,
+            "sequence_number": sequence_number,
+            "lsa_headers": lsahdrs,
+        }
+
+    def serialize_tail(self):
+        flags = ((self.i_flag & 0x1) << 2) ^ \
+                ((self.m_flag & 0x1) << 1) ^ \
+                (self.ms_flag & 0x1)
+        head = bytearray(struct.pack(self._PACK_STR, self.mtu,
+                                     self.options, flags,
+                                     self.sequence_number))
+        try:
+            return head + reduce(lambda a, b: a+b,
+                                 (hdr.serialize() for hdr in self.lsa_headers))
+        except TypeError:
+            return head
+
+
[email protected]_type(OSPF_MSG_LS_REQ)
+class OSPFLSReq(OSPFMessage):
+    _MIN_LEN = OSPFMessage._HDR_LEN
+
+    class Request(StringifyMixin):
+        _PACK_STR = '!I4s4s'
+        _PACK_LEN = struct.calcsize(_PACK_STR)
+
+        def __init__(self, type_=OSPF_UNKNOWN_LSA, id_='0.0.0.0',
+                     adv_router='0.0.0.0'):
+            self.type_ = type_
+            self.id = id_
+            self.adv_router = adv_router
+
+        @classmethod
+        def parser(cls, buf):
+            if len(buf) < cls._PACK_LEN:
+                raise stream_parser.StreamParser.TooSmallException(
+                    '%d < %d' % (len(buf), cls._PACK_LEN))
+            link = buf[:cls._PACK_LEN]
+            rest = buf[cls._PACK_LEN:]
+            (type_, id_, adv_router) = struct.unpack_from(cls._PACK_STR,
+                                                          buffer(link))
+            id_ = addrconv.ipv4.bin_to_text(id_)
+            adv_router = addrconv.ipv4.bin_to_text(adv_router)
+            return cls(type_, id_, adv_router), rest
+
+        def serialize(self):
+            id_ = addrconv.ipv4.text_to_bin(self.id)
+            adv_router = addrconv.ipv4.text_to_bin(self.adv_router)
+            return bytearray(struct.pack(self._PACK_STR, self.type_,
+                                         id_, adv_router))
+
+    def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
+                 au_type=1, authentication=0, checksum=None, version=_VERSION,
+                 lsa_requests=[]):
+        super(OSPFLSReq, self).__init__(OSPF_MSG_LS_REQ, length, router_id,
+                                        area_id, au_type, authentication,
+                                        checksum, version)
+        self.lsa_requests = lsa_requests
+
+    @classmethod
+    def parser(cls, buf):
+        reqs = []
+        while buf:
+            req, buf = cls.Request.parser(buf)
+            reqs.append(req)
+        return {
+            "lsa_requests": reqs,
+        }
+
+    def serialize_tail(self):
+        return reduce(lambda a, b: a+b,
+                      (req.serialize() for req in self.lsa_requests))
+
+
[email protected]_type(OSPF_MSG_LS_UPD)
+class OSPFLSUpd(OSPFMessage):
+    _PACK_STR = '!I'
+    _PACK_LEN = struct.calcsize(_PACK_STR)
+    _MIN_LEN = OSPFMessage._HDR_LEN + _PACK_LEN
+
+    def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
+                 au_type=1, authentication=0, checksum=None, version=_VERSION,
+                 lsas=[]):
+        super(OSPFLSUpd, self).__init__(OSPF_MSG_LS_UPD, length, router_id,
+                                        area_id, au_type, authentication,
+                                        checksum, version)
+        self.lsas = lsas
+
+    @classmethod
+    def parser(cls, buf):
+        binnum = buf[:cls._PACK_LEN]
+        (num,) = struct.unpack_from(cls._PACK_STR, buffer(binnum))
+
+        buf = buf[cls._PACK_LEN:]
+        lsas = []
+        while buf:
+            lsa, cls, buf = LSA.parser(buf)
+            lsas.append(lsa)
+        assert(len(lsas) == num)
+        return {
+            "lsas": lsas,
+        }
+
+    def serialize_tail(self):
+        head = bytearray(struct.pack(self._PACK_STR, len(self.lsas)))
+        try:
+            return head + reduce(lambda a, b: a+b,
+                                 (lsa.serialize() for lsa in self.lsas))
+        except TypeError:
+            return head
+
+
[email protected]_type(OSPF_MSG_LS_ACK)
+class OSPFLSAck(OSPFMessage):
+    _MIN_LEN = OSPFMessage._HDR_LEN
+
+    def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
+                 au_type=1, authentication=0, checksum=None, version=_VERSION,
+                 lsa_headers=[]):
+        super(OSPFLSAck, self).__init__(OSPF_MSG_LS_ACK, length, router_id,
+                                        area_id, au_type, authentication,
+                                        checksum, version)
+        self.lsa_headers = lsa_headers
+
+    @classmethod
+    def parser(cls, buf):
+        lsahdrs = []
+        while buf:
+            kwargs, buf = LSAHeader.parser(buf)
+            lsahdrs.append(LSAHeader(**kwargs))
+        return {
+            "lsa_headers": lsahdrs,
+        }
+
+    def serialize_tail(self):
+        return reduce(lambda a, b: a+b,
+                      (hdr.serialize() for hdr in self.lsa_headers))
diff --git a/ryu/ofproto/inet.py b/ryu/ofproto/inet.py
index 6990b72..64f59fd 100644
--- a/ryu/ofproto/inet.py
+++ b/ryu/ofproto/inet.py
@@ -26,5 +26,6 @@ IPPROTO_AH = 51
 IPPROTO_ICMPV6 = 58
 IPPROTO_NONE = 59
 IPPROTO_DSTOPTS = 60
+IPPROTO_OSPF = 89
 IPPROTO_VRRP = 112
 IPPROTO_SCTP = 132
-- 
1.8.1.2


------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to