Changes v1 -> v2:

- add automatically-calculation of the checksum

Signed-off-by: Yuichi Ito <[email protected]>
---
 doc/source/library_packet_ref.rst  |    4 +
 ryu/lib/packet/igmp.py             |  112 +++++++++++++++++++++++++++
 ryu/lib/packet/ipv4.py             |    2 +
 ryu/ofproto/inet.py                |    1 +
 ryu/tests/unit/packet/test_igmp.py |  147 ++++++++++++++++++++++++++++++++++++
 5 files changed, 266 insertions(+)
 create mode 100644 ryu/lib/packet/igmp.py
 create mode 100644 ryu/tests/unit/packet/test_igmp.py

diff --git a/doc/source/library_packet_ref.rst 
b/doc/source/library_packet_ref.rst
index 351e95e..ea9d07b 100644
--- a/doc/source/library_packet_ref.rst
+++ b/doc/source/library_packet_ref.rst
@@ -80,3 +80,7 @@ Protocol Header classes
    :members:
 .. autoclass:: ryu.lib.packet.bpdu.RstBPDUs
    :members:
+
+.. autoclass:: ryu.lib.packet.igmp.igmp
+   :members:
+
diff --git a/ryu/lib/packet/igmp.py b/ryu/lib/packet/igmp.py
new file mode 100644
index 0000000..1081e4d
--- /dev/null
+++ b/ryu/lib/packet/igmp.py
@@ -0,0 +1,112 @@
+# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Internet Group Management Protocol(IGMP) packet parser/serializer
+
+RFC 1112
+IGMP v1 format
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |Version| Type  |    Unused     |           Checksum            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                         Group Address                         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+RFC 2236
+IGMP v2 format
+
+    0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |      Type     | Max Resp Time |           Checksum            |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                         Group Address                         |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+"""
+
+import struct
+
+from ryu.lib import addrconv
+from ryu.lib.packet import packet_base
+from ryu.lib.packet import packet_utils
+
+
+IGMP_TYPE_QUERY = 0x11
+IGMP_TYPE_REPORT_V1 = 0x12
+IGMP_TYPE_REPORT_V2 = 0x16
+IGMP_TYPE_LEAVE = 0x17
+
+
+class igmp(packet_base.PacketBase):
+    """
+    Internet Group Management Protocol(IGMP, RFC 1112, RFC 2236)
+    header encoder/decoder class.
+
+    http://www.ietf.org/rfc/rfc1112.txt
+
+    http://www.ietf.org/rfc/rfc2236.txt
+
+    An instance has the following attributes at least.
+    Most of them are same to the on-wire counterparts but in host byte
+    order.
+    __init__ takes the correspondig args in this order.
+
+    =============== ====================================================
+    Attribute       Description
+    =============== ====================================================
+    msgtype         a message type for v2, or a combination of
+                    version and a message type for v1.
+    maxresp         max response time in unit of 1/10 second. it is
+                    meaningful only in Query Message.
+    csum            a check sum value. 0 means automatically-calculate
+                    when encoding.
+    address         a group address value.
+    =============== ====================================================
+
+    * NOTE: IGMP v3(RFC 3376) is not supported yet.
+    """
+    _PACK_STR = '!BBH4s'
+    _MIN_LEN = struct.calcsize(_PACK_STR)
+
+    def __init__(self, msgtype, maxresp, csum, address):
+        super(igmp, self).__init__()
+        self.msgtype = msgtype
+        self.maxresp = maxresp
+        self.csum = csum
+        self.address = address
+
+    @classmethod
+    def parser(cls, buf):
+        assert cls._MIN_LEN <= len(buf)
+        (msgtype, maxresp, csum, address
+         ) = struct.unpack_from(cls._PACK_STR, buf)
+        return (cls(msgtype, maxresp, csum,
+                    addrconv.ipv4.bin_to_text(address)),
+                None,
+                buf[cls._MIN_LEN:])
+
+    def serialize(self, payload, prev):
+        hdr = bytearray(struct.pack(self._PACK_STR, self.msgtype,
+                        self.maxresp, self.csum,
+                        addrconv.ipv4.text_to_bin(self.address)))
+
+        if self.csum == 0:
+            self.csum = packet_utils.checksum(hdr)
+            struct.pack_into('!H', hdr, 2, self.csum)
+
+        return hdr
diff --git a/ryu/lib/packet/ipv4.py b/ryu/lib/packet/ipv4.py
index 8a07c81..032e425 100644
--- a/ryu/lib/packet/ipv4.py
+++ b/ryu/lib/packet/ipv4.py
@@ -18,6 +18,7 @@ import struct
 from . import packet_base
 from . import packet_utils
 from . import icmp
+from . import igmp
 from . import udp
 from . import tcp
 from ryu.ofproto import inet
@@ -134,5 +135,6 @@ class ipv4(packet_base.PacketBase):
         return hdr

 ipv4.register_packet_type(icmp.icmp, inet.IPPROTO_ICMP)
+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)
diff --git a/ryu/ofproto/inet.py b/ryu/ofproto/inet.py
index d0ce694..6990b72 100644
--- a/ryu/ofproto/inet.py
+++ b/ryu/ofproto/inet.py
@@ -17,6 +17,7 @@
 IPPROTO_IP = 0
 IPPROTO_HOPOPTS = 0
 IPPROTO_ICMP = 1
+IPPROTO_IGMP = 2
 IPPROTO_TCP = 6
 IPPROTO_UDP = 17
 IPPROTO_ROUTING = 43
diff --git a/ryu/tests/unit/packet/test_igmp.py 
b/ryu/tests/unit/packet/test_igmp.py
new file mode 100644
index 0000000..e5a810b
--- /dev/null
+++ b/ryu/tests/unit/packet/test_igmp.py
@@ -0,0 +1,147 @@
+# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import unittest
+import inspect
+import logging
+
+from struct import pack, unpack_from
+from nose.tools import ok_, eq_, raises
+from ryu.ofproto import ether
+from ryu.ofproto import inet
+from ryu.lib.packet.ethernet import ethernet
+from ryu.lib.packet.ipv4 import ipv4
+from ryu.lib.packet.packet import Packet
+from ryu.lib.packet.packet_utils import checksum
+from ryu.lib import addrconv
+from ryu.lib.packet.igmp import igmp
+from ryu.lib.packet.igmp import IGMP_TYPE_QUERY
+
+LOG = logging.getLogger(__name__)
+
+
+class Test_igmp(unittest.TestCase):
+    """ Test case for Internet Group Management Protocol
+    """
+    def setUp(self):
+        self.msgtype = IGMP_TYPE_QUERY
+        self.maxresp = 100
+        self.csum = 0
+        self.address = '225.0.0.1'
+
+        self.buf = pack(igmp._PACK_STR, self.msgtype, self.maxresp,
+                        self.csum,
+                        addrconv.ipv4.text_to_bin(self.address))
+
+        self.g = igmp(self.msgtype, self.maxresp, self.csum,
+                      self.address)
+
+    def tearDown(self):
+        pass
+
+    def find_protocol(self, pkt, name):
+        for p in pkt.protocols:
+            if p.protocol_name == name:
+                return p
+
+    def test_init(self):
+        eq_(self.msgtype, self.g.msgtype)
+        eq_(self.maxresp, self.g.maxresp)
+        eq_(self.csum, self.g.csum)
+        eq_(self.address, self.g.address)
+
+    def test_parser(self):
+        _res = self.g.parser(self.buf)
+        if type(_res) is tuple:
+            res = _res[0]
+        else:
+            res = _res
+
+        eq_(res.msgtype, self.msgtype)
+        eq_(res.maxresp, self.maxresp)
+        eq_(res.csum, self.csum)
+        eq_(res.address, self.address)
+
+    def test_serialize(self):
+        data = bytearray()
+        prev = None
+        buf = self.g.serialize(data, prev)
+
+        res = unpack_from(igmp._PACK_STR, buffer(buf))
+
+        eq_(res[0], self.msgtype)
+        eq_(res[1], self.maxresp)
+        eq_(res[2], checksum(self.buf))
+        eq_(res[3], addrconv.ipv4.text_to_bin(self.address))
+
+    def _build_igmp(self):
+        dl_dst = '11:22:33:44:55:66'
+        dl_src = 'aa:bb:cc:dd:ee:ff'
+        dl_type = ether.ETH_TYPE_IP
+        e = ethernet(dl_dst, dl_src, dl_type)
+
+        total_length = 20 + igmp._MIN_LEN
+        nw_proto = inet.IPPROTO_IGMP
+        nw_dst = '11.22.33.44'
+        nw_src = '55.66.77.88'
+        i = ipv4(total_length=total_length, src=nw_src, dst=nw_dst,
+                 proto=nw_proto)
+
+        p = Packet()
+
+        p.add_protocol(e)
+        p.add_protocol(i)
+        p.add_protocol(self.g)
+        p.serialize()
+        return p
+
+    def test_build_igmp(self):
+        p = self._build_igmp()
+
+        e = self.find_protocol(p, "ethernet")
+        ok_(e)
+        eq_(e.ethertype, ether.ETH_TYPE_IP)
+
+        i = self.find_protocol(p, "ipv4")
+        ok_(i)
+        eq_(i.proto, inet.IPPROTO_IGMP)
+
+        g = self.find_protocol(p, "igmp")
+        ok_(g)
+
+        eq_(g.msgtype, self.msgtype)
+        eq_(g.maxresp, self.maxresp)
+        eq_(g.csum, checksum(self.buf))
+        eq_(g.address, self.address)
+
+    def test_to_string(self):
+        igmp_values = {'msgtype': repr(self.msgtype),
+                       'maxresp': repr(self.maxresp),
+                       'csum': repr(self.csum),
+                       'address': repr(self.address)}
+        _g_str = ','.join(['%s=%s' % (k, igmp_values[k])
+                           for k, v in inspect.getmembers(self.g)
+                           if k in igmp_values])
+        g_str = '%s(%s)' % (igmp.__name__, _g_str)
+
+        eq_(str(self.g), g_str)
+        eq_(repr(self.g), g_str)
+
+    @raises(Exception)
+    def test_malformed_igmp(self):
+        m_short_buf = self.buf[1:igmp._MIN_LEN]
+        igmp.parser(m_short_buf)
-- 
1.7.10.4


------------------------------------------------------------------------------
Get 100% visibility into Java/.NET code with AppDynamics Lite!
It's a free troubleshooting tool designed for production.
Get down to code-level detail for bottlenecks, with <2% overhead. 
Download for free and get started troubleshooting in minutes. 
http://pubads.g.doubleclick.net/gampad/clk?id=48897031&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to