Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp>
---
Changes v1 -> v2:
- exception when non vrrp packet
- checksum
---
 ryu/lib/packet/vrrp.py |  555 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 555 insertions(+)
 create mode 100644 ryu/lib/packet/vrrp.py

diff --git a/ryu/lib/packet/vrrp.py b/ryu/lib/packet/vrrp.py
new file mode 100644
index 0000000..f98d6ae
--- /dev/null
+++ b/ryu/lib/packet/vrrp.py
@@ -0,0 +1,555 @@
+# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
+# Copyright (C) 2013 Isaku Yamahata <yamahata at private email ne jp>
+#
+# 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.
+
+"""
+VRRP packet parser/serializer
+
+RFC 3768
+VRRP v2 packet 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  | Virtual Rtr ID|   Priority    | Count IP Addrs|
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |   Auth Type   |   Adver Int   |          Checksum             |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                         IP Address (1)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                            .                                  |
+   |                            .                                  |
+   |                            .                                  |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                         IP Address (n)                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                     Authentication Data (1)                   |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                     Authentication Data (2)                   |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+RFC 5798
+VRRP v3 packet 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
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                    IPv4 Fields or IPv6 Fields                 |
+   ...                                                             ...
+    |                                                               |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |Version| Type  | Virtual Rtr ID|   Priority    |Count IPvX Addr|
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |(rsvd) |     Max Adver Int     |          Checksum             |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    |                                                               |
+    +                                                               +
+    |                       IPvX Address(es)                        |
+    +                                                               +
+    +                                                               +
+    +                                                               +
+    +                                                               +
+    |                                                               |
+    +                                                               +
+    |                                                               |
+    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+"""
+
+import netaddr
+import struct
+
+from ryu.lib.packet import ethernet
+from ryu.lib.packet import ipv4
+from ryu.lib.packet import ipv6
+from ryu.lib.packet import packet
+from ryu.lib.packet import packet_base
+from ryu.lib.packet import packet_utils
+from ryu.lib.packet import vlan
+from ryu.ofproto import ether
+from ryu.ofproto import inet
+
+
+# IPv4
+# the LSB 8 bits is used for VRID
+VRRP_IPV4_SRC_MAC_ADDRESS_STR = '00:00:5E:00:01:00'
+VRRP_IPV4_SRC_MAC_ADDRESS = netaddr.EUI(VRRP_IPV4_SRC_MAC_ADDRESS_STR).packed
+VRRP_IPV4_DST_MAC_ADDRESS_STR = '01:00:5E:00:00:12'
+VRRP_IPV4_DST_MAC_ADDRESS = netaddr.EUI(VRRP_IPV4_DST_MAC_ADDRESS_STR).packed
+VRRP_IPV4_DST_ADDRESS_STR = '224.0.0.18'
+VRRP_IPV4_DST_ADDRESS = netaddr.IPAddress(VRRP_IPV4_DST_ADDRESS_STR).value
+VRRP_IPV4_TTL = 255
+
+
+def vrrp_ipv4_src_mac_address(vrid):
+    return VRRP_IPV4_SRC_MAC_ADDRESS[:-1] + chr(vrid)
+
+
+# IPv6
+# the LSB 8 bits is used for VRID
+VRRP_IPV6_SRC_MAC_ADDRESS_STR = '00:00:5E:00:02:00'
+VRRP_IPV6_SRC_MAC_ADDRESS = netaddr.EUI(VRRP_IPV6_SRC_MAC_ADDRESS_STR).packed
+VRRP_IPV6_DST_MAC_ADDRESS_STR = '33:33:00:00:00:12'
+VRRP_IPV6_DST_MAC_ADDRESS = netaddr.EUI(VRRP_IPV6_DST_MAC_ADDRESS_STR).packed
+VRRP_IPV6_DST_ADDRESS_STR = 'FF02:0:0:0:0:0:0:12'
+VRRP_IPV6_DST_ADDRESS = netaddr.IPAddress(VRRP_IPV6_DST_ADDRESS_STR).packed
+VRRP_IPV6_HOP_LIMIT = 255
+
+
+def vrrp_ipv6_src_mac_address(vrid):
+    return VRRP_IPV6_SRC_MAC_ADDRESS[:-1] + chr(vrid)
+
+
+VRRP_VERSION_SHIFT = 4
+VRRP_TYPE_MASK = 0xf
+
+
+def vrrp_from_version_type(version_type):
+    return (version_type >> VRRP_VERSION_SHIFT, version_type & VRRP_TYPE_MASK)
+
+
+def vrrp_to_version_type(version, type_):
+    return (version << VRRP_VERSION_SHIFT) | type_
+
+
+# VRRP version
+VRRP_VERSION_V2 = 2
+VRRP_VERSION_V3 = 3
+
+# VRRP type
+VRRP_TYPE_ADVERTISEMENT = 1
+
+# VRRP VRID: 0 isn't used
+VRRP_VRID_MIN = 1
+VRRP_VRID_MAX = 255
+
+# VRRP priority
+VRRP_PRIORITY_MIN = 0
+VRRP_PRIORITY_MAX = 255
+VRRP_PRIORITY_RELEASE_RESPONSIBILITY = 0
+VRRP_PRIORITY_BACKUP_MIN = 1
+VRRP_PRIORITY_BACKUP_DEFAULT = 100
+VRRP_PRIORITY_BACKUP_MAX = 254
+VRRP_PRIORITY_ADDRESS_OWNER = 255
+
+# VRRP auth type (VRRP v2 only)
+VRRP_AUTH_NO_AUTH = 0
+VRRP_AUTH_RESERVED1 = 1
+VRRP_AUTH_RESERVED2 = 2
+VRRP_AUTH_DATA1 = 0
+VRRP_AUTH_DATA2 = 0
+VRRP_AUTH_DATA = (VRRP_AUTH_DATA1, VRRP_AUTH_DATA2)
+
+# VRRP Max advertisement interval
+VRRP_MAX_ADVER_INT_DEFAULT_IN_SEC = 1   # 1 second
+
+VRRP_V3_MAX_ADVER_INT_MASK = 0xfff      # in centiseconds
+VRRP_V3_MAX_ADVER_INT_DEFAULT = 100     # = 1 second
+VRRP_V3_MAX_ADVER_INT_MIN = 1           # don't allow 0
+VRRP_V3_MAX_ADVER_INT_MAX = 0xfff
+
+VRRP_V2_MAX_ADVER_INT_MASK = 0xff       # in seconds
+VRRP_V2_MAX_ADVER_INT_DEFAULT = 1       # 1 second
+VRRP_V2_MAX_ADVER_INT_MIN = 1           # don't allow 0
+VRRP_V2_MAX_ADVER_INT_MAX = 0xff
+
+
+def is_ipv6(ip_address):
+    if type(ip_address) == int:
+        return False
+
+    assert type(ip_address) == str
+    assert len(ip_address) == 16
+    return True
+
+
+class vrrp(packet_base.PacketBase):
+    _VERSION_PACK_STR = '!B'
+    _IPV4_ADDRESS_PACK_STR_RAW = 'I'
+    _IPV4_ADDRESS_PACK_STR = '!' + _IPV4_ADDRESS_PACK_STR_RAW
+    _IPV4_ADDRESS_LEN = struct.calcsize(_IPV4_ADDRESS_PACK_STR)
+    _IPV6_ADDRESS_LEN = 16
+    _IPV6_ADDRESS_PACK_STR_RAW = '%ds' % _IPV6_ADDRESS_LEN
+    _IPV6_ADDRESS_PACK_STR = '!' + _IPV6_ADDRESS_PACK_STR_RAW
+    _IPV6_ADDRESS_LEN = struct.calcsize(_IPV6_ADDRESS_PACK_STR)
+
+    _VRRP_VERSIONS = {}
+    _SEC_IN_MAX_ADVER_INT_UNIT = {}
+
+    @staticmethod
+    def get_payload(packet_):
+        protocols = packet_.protocols
+
+        try:
+            may_ip, may_vrrp = protocols[-2], protocols[-1]
+            if isinstance(may_vrrp, bytearray):
+                may_ip, may_vrrp = protocols[-3], protocols[-2]
+        except IndexError:
+            return None, None
+
+        if (not isinstance(may_ip, ipv4.ipv4) and
+                not isinstance(may_ip, ipv6.ipv6)):
+            return None, None
+        if not isinstance(may_vrrp, vrrp):
+            return None, None
+        return may_ip, may_vrrp
+
+    @classmethod
+    def register_vrrp_version(cls, version,
+                              sec_in_max_adver_int_unit):
+        def _register_vrrp_version(cls_):
+            cls._VRRP_VERSIONS[version] = cls_
+            cls._SEC_IN_MAX_ADVER_INT_UNIT[version] = sec_in_max_adver_int_unit
+            return cls_
+        return _register_vrrp_version
+
+    @staticmethod
+    def sec_to_max_adver_int(version, seconds):
+        return int(seconds * vrrp._SEC_IN_MAX_ADVER_INT_UNIT[version])
+
+    @staticmethod
+    def max_adver_int_to_sec(version, max_adver_int):
+        return float(max_adver_int) / vrrp._SEC_IN_MAX_ADVER_INT_UNIT[version]
+
+    def __init__(self, version, type_, vrid, priority, count_ip,
+                 max_adver_int, checksum, ip_addresses,
+
+                 # auth_type/auth_data is for vrrp v2
+                 auth_type=None, auth_data=None):
+        super(vrrp, self).__init__()
+        self.version = version
+        self.type = type_
+        self.vrid = vrid
+        self.priority = priority
+        self.count_ip = count_ip
+        self.max_adver_int = max_adver_int
+
+        self.checksum = checksum
+        self.ip_addresses = ip_addresses
+        assert len(ip_addresses) == self.count_ip
+
+        self.auth_type = auth_type
+        self.auth_data = auth_data
+
+        self._is_ipv6 = is_ipv6(self.ip_addresses[0])
+        self.length = len(self)
+        self.identification = 0         # used for ipv4 identification
+
+    def checksum_ok(self, ipvx, vrrp_buf):
+        cls_ = self._VRRP_VERSIONS[self.version]
+        return cls_.checksum_ok(self, ipvx, vrrp_buf)
+
+    @property
+    def max_adver_int_in_sec(self):
+        # return seconds of float as time.sleep() accepts such type.
+        return self.max_adver_int_to_sec(self.version, self.max_adver_int)
+
+    @property
+    def is_ipv6(self):
+        return self._is_ipv6
+
+    def __len__(self):
+        cls_ = self._VRRP_VERSIONS[self.version]
+        return cls_.__len__(self)
+
+    @staticmethod
+    def create_version(version, type_, vrid, priority, max_adver_int,
+                       ip_addresses, auth_type=None, auth_data=None):
+        cls_ = vrrp._VRRP_VERSIONS.get(version, None)
+        if not cls_:
+            raise ValueError('unknown VRRP version %d' % version)
+
+        if priority is None:
+            priority = VRRP_PRIORITY_BACKUP_DEFAULT
+        count_ip = len(ip_addresses)
+        if max_adver_int is None:
+            max_adver_int = cls_.sec_to_max_adver_int(
+                VRRP_MAX_ADVER_INT_DEFAULT_IN_SEC)
+        return cls_(version, type_, vrid, priority, count_ip, max_adver_int,
+                    None, ip_addresses,
+                    auth_type=auth_type, auth_data=auth_data)
+
+    def get_identification(self):
+        self.identification += 1
+        self.identification &= 0xffff
+        if self.identification == 0:
+            self.identification += 1
+            self.identification &= 0xffff
+        return self.identification
+
+    def create_packet(self, primary_ip_address, vlan_id=None):
+        if self.is_ipv6:
+            traffic_class = 0xc0        # set tos to internetwork control
+            flow_label = 0
+            payload_length = ipv6.ipv6._MIN_LEN + self.length   # XXX _MIN_LEN
+            e = ethernet.ethernet(VRRP_IPV6_DST_MAC_ADDRESS,
+                                  vrrp_ipv6_src_mac_address(self.vrid),
+                                  ether.ETH_TYPE_IPV6)
+            ip = ipv6.ipv6(6, traffic_class, flow_label, payload_length,
+                           inet.IPPROTO_VRRP, VRRP_IPV6_HOP_LIMIT,
+                           primary_ip_address, VRRP_IPV6_DST_ADDRESS)
+        else:
+            header_length = ipv4.ipv4._MIN_LEN / 4      # XXX _MIN_LEN
+            total_length = 0
+            tos = 0xc0  # set tos to internetwork control
+            identification = self.get_identification()
+            e = ethernet.ethernet(VRRP_IPV4_DST_MAC_ADDRESS,
+                                  vrrp_ipv4_src_mac_address(self.vrid),
+                                  ether.ETH_TYPE_IP)
+            ip = ipv4.ipv4(4, header_length, tos, total_length, identification,
+                           0, 0, VRRP_IPV4_TTL, inet.IPPROTO_VRRP, 0,
+                           primary_ip_address, VRRP_IPV4_DST_ADDRESS)
+
+        p = packet.Packet()
+        p.add_protocol(e)
+        if vlan_id is not None:
+            vlan_ = vlan.vlan(0, 0, vlan_id, e.ethertype)
+            e.ethertype = ether.ETH_TYPE_8021Q
+            p.add_protocol(vlan_)
+        p.add_protocol(ip)
+        p.add_protocol(self)
+        return p
+
+    @classmethod
+    def parser(cls, buf):
+        (version_type,) = struct.unpack_from(cls._VERSION_PACK_STR, buf)
+        version, _type = vrrp_from_version_type(version_type)
+        cls_ = cls._VRRP_VERSIONS[version]
+        return cls_.parser(buf)
+
+    @staticmethod
+    def serialize_static(vrrp_, prev):
+        # self can be a instance of vrrpv2 or vrrpv3.
+        assert isinstance(vrrp_, vrrp)
+        cls = vrrp._VRRP_VERSIONS[vrrp_.version]
+        return cls.serialize_static(vrrp_, prev)
+
+    def serialize(self, payload, prev):
+        return self.serialize_static(self, prev)
+
+    @staticmethod
+    def is_valid_ttl(ipvx):
+        version = ipvx.version
+        if version == 4:
+            return ipvx.ttl == VRRP_IPV4_TTL
+        if version == 6:
+            return ipvx.hop_limit == VRRP_IPV6_HOP_LIMIT
+
+        raise ValueError('invalid ip version %d' % version)
+
+    def is_valid(self):
+        cls = self._VRRP_VERSIONS.get(self.version, None)
+        if None:
+            return False
+        return cls.is_valid(self)
+
+
+# max_adver_int is in seconds
+@vrrp.register_vrrp_version(VRRP_VERSION_V2, 1)
+class vrrpv2(vrrp):
+    _PACK_STR = '!BBBBBBH'
+    _MIN_LEN = struct.calcsize(_PACK_STR)
+    _CHECKSUM_PACK_STR = '!H'
+    _CHECKSUM_OFFSET = 6
+    _AUTH_DATA_PACK_STR = '!II'
+    _AUTH_DATA_LEN = struct.calcsize('!II')
+
+    def __len__(self):
+        return (self._MIN_LEN + self._IPV4_ADDRESS_LEN * self.count_ip +
+                self._AUTH_DATA_LEN)
+
+    def checksum_ok(self, ipvx, vrrp_buf):
+        return packet_utils.checksum(vrrp_buf) == 0
+
+    @staticmethod
+    def create(type_, vrid, priority, max_adver_int, ip_addresses):
+        return vrrp.create_version(VRRP_VERSION_V2, type_, vrid, priority,
+                                   max_adver_int,
+                                   ip_addresses,
+                                   auth_type=VRRP_AUTH_NO_AUTH,
+                                   auth_data=VRRP_AUTH_DATA)
+
+    @staticmethod
+    def _ip_addresses_pack_str(count_ip):
+        return '!' + vrrpv2._IPV4_ADDRESS_PACK_STR_RAW * count_ip
+
+    @classmethod
+    def parser(cls, buf):
+        (version_type, vrid, priority, count_ip, auth_type, adver_int,
+         checksum) = struct.unpack_from(cls._PACK_STR, buf)
+        (version, type_) = vrrp_from_version_type(version_type)
+
+        offset = cls._MIN_LEN
+        ip_addresses_pack_str = cls._ip_addresses_pack_str(count_ip)
+        ip_addresses = struct.unpack_from(ip_addresses_pack_str, buf, offset)
+
+        offset += struct.calcsize(ip_addresses_pack_str)
+        auth_data = struct.unpack_from(cls._AUTH_DATA_PACK_STR, buf, offset)
+
+        return cls(version, type_, vrid, priority, count_ip, adver_int,
+                   checksum, ip_addresses, auth_type, auth_data), None
+
+    @staticmethod
+    def serialize_static(vrrp_, prev):
+        assert not vrrp_.is_ipv6        # vrrpv2 defines only IPv4
+        ip_addresses_pack_str = vrrpv2._ip_addresses_pack_str(vrrp_.count_ip)
+        ip_addresses_len = struct.calcsize(ip_addresses_pack_str)
+        vrrp_len = vrrpv2._MIN_LEN + ip_addresses_len + vrrpv2._AUTH_DATA_LEN
+
+        checksum = False
+        if vrrp_.checksum is None:
+            checksum = True
+            vrrp_.checksum = 0
+
+        if vrrp_.auth_type is None:
+            vrrp_.auth_type = VRRP_AUTH_NO_AUTH
+        if vrrp_.auth_data is None:
+            vrrp_.auth_data = VRRP_AUTH_DATA
+
+        buf = bytearray(vrrp_len)
+        offset = 0
+        struct.pack_into(vrrpv2._PACK_STR, buf, offset,
+                         vrrp_to_version_type(vrrp_.version, vrrp_.type),
+                         vrrp_.vrid, vrrp_.priority,
+                         vrrp_.count_ip, vrrp_.auth_type, vrrp_.max_adver_int,
+                         vrrp_.checksum)
+        offset += vrrpv2._MIN_LEN
+        struct.pack_into(ip_addresses_pack_str, buf, offset,
+                         *vrrp_.ip_addresses)
+        offset += ip_addresses_len
+        struct.pack_into(vrrpv2._AUTH_DATA_PACK_STR, buf, offset,
+                         *vrrp_.auth_data)
+        if checksum:
+            vrrp_.checksum = packet_utils.checksum(buf)
+            struct.pack_into(vrrpv2._CHECKSUM_PACK_STR, buf,
+                             vrrpv2._CHECKSUM_OFFSET, vrrp_.checksum)
+        return buf
+
+    def is_valid(self):
+        return (self.version == VRRP_VERSION_V2 and
+                self.type == VRRP_TYPE_ADVERTISEMENT and
+                VRRP_VRID_MIN <= self.vrid and self.vrid <= VRRP_VRID_MAX and
+                VRRP_PRIORITY_MIN <= self.vrid and
+                self.vrid <= VRRP_PRIORITY_MAX and
+                self.auth_type == VRRP_AUTH_NO_AUTH and
+                VRRP_V2_MAX_ADVER_INT_MIN <= self.max_adver_int and
+                self.max_adver_int <= VRRP_V2_MAX_ADVER_INT_MAX and
+                self.count_ip == len(self.ip_addresses))
+
+
+# max_adver_int is in centi seconds: 1 second = 100 centiseconds
+@vrrp.register_vrrp_version(VRRP_VERSION_V3, 100)
+class vrrpv3(vrrp):
+    _PACK_STR = '!BBBBHH'
+    _MIN_LEN = struct.calcsize(_PACK_STR)
+    _CHECKSUM_PACK_STR = '!H'
+    _CHECKSUM_OFFSET = 6
+
+    def __len__(self):
+        if self.is_ipv6:
+            address_len = self._IPV6_ADDRESS_LEN
+        else:
+            address_len = self._IPV4_ADDRESS_LEN
+        return self._MIN_LEN + address_len * self.count_ip
+
+    def checksum_ok(self, ipvx, vrrp_buf):
+        # There are two interpretation of IPv4 checksum
+        # include IPv4 pseudo header or not.
+        # http://www.ietf.org/mail-archive/web/vrrp/current/msg01473.html
+        # if not self.is_ipv6:
+        #     return packet_utils.checksum(vrrp_buf) == 0
+        return packet_utils.checksum_ip(ipvx, self.length, vrrp_buf) == 0
+
+    @staticmethod
+    def create(type_, vrid, priority, max_adver_int, ip_addresses):
+        return vrrp.create_version(VRRP_VERSION_V3, type_, vrid, priority,
+                                   max_adver_int, ip_addresses)
+
+    @classmethod
+    def parser(cls, buf):
+        (version_type, vrid, priority, count_ip, max_adver_int,
+         checksum) = struct.unpack_from(cls._PACK_STR, buf)
+        (version, type_) = vrrp_from_version_type(version_type)
+
+        # _rsvd = (max_adver_int & ~VRRP_V3_MAX_ADVER_INT_MASK) >> 12
+        # asssert _rsvd == 0
+        max_adver_int &= VRRP_V3_MAX_ADVER_INT_MASK
+
+        offset = cls._MIN_LEN
+        address_len = (len(buf) - offset) / count_ip
+        # Address version (IPv4 or IPv6) is determined by network layer
+        # header type.
+        # Unfortunately it isn't available. Guess it by vrrp packet length.
+        if address_len == cls._IPV4_ADDRESS_LEN:
+            pack_str = '!' + cls._IPV4_ADDRESS_PACK_STR_RAW * count_ip
+        elif address_len == cls._IPV6_ADDRESS_LEN:
+            pack_str = '!' + cls._IPV6_ADDRESS_PACK_STR_RAW * count_ip
+        else:
+            raise ValueError(
+                'unknown address version address_len %d count_ip %d' % (
+                    address_len, count_ip))
+
+        ip_addresses = struct.unpack_from(pack_str, buf, offset)
+        return cls(version, type_, vrid, priority,
+                   count_ip, max_adver_int, checksum, ip_addresses), None
+
+    @staticmethod
+    def serialize_static(vrrp_, prev):
+        if isinstance(prev, ipv4.ipv4):
+            assert type(vrrp_.ip_addresses[0]) == int
+            ip_address_pack_raw = vrrpv3._IPV4_ADDRESS_PACK_STR_RAW
+        elif isinstance(prev, ipv6.ipv6):
+            assert type(vrrp_.ip_addresses[0]) == str
+            assert len(vrrp_.ip_addresses[0]) == vrrp._IPV6_ADDRESS_LEN
+            ip_address_pack_raw = vrrpv3._IPV6_ADDRESS_PACK_STR_RAW
+        else:
+            raise ValueError('Unkown network layer %s' % type(prev))
+
+        ip_addresses_pack_str = '!' + ip_address_pack_raw * vrrp_.count_ip
+        ip_addresses_len = struct.calcsize(ip_addresses_pack_str)
+        vrrp_len = vrrpv3._MIN_LEN + ip_addresses_len
+
+        checksum = False
+        if vrrp_.checksum is None:
+            checksum = True
+            vrrp_.checksum = 0
+
+        buf = bytearray(vrrp_len)
+        assert vrrp_.max_adver_int <= VRRP_V3_MAX_ADVER_INT_MASK
+        struct.pack_into(vrrpv3._PACK_STR, buf, 0,
+                         vrrp_to_version_type(vrrp_.version, vrrp_.type),
+                         vrrp_.vrid, vrrp_.priority,
+                         vrrp_.count_ip, vrrp_.max_adver_int, vrrp_.checksum)
+        struct.pack_into(ip_addresses_pack_str, buf, vrrpv3._MIN_LEN,
+                         *vrrp_.ip_addresses)
+
+        if checksum:
+            vrrp_.checksum = packet_utils.checksum_ip(prev, len(buf), buf)
+            struct.pack_into(vrrpv3._CHECKSUM_PACK_STR, buf,
+                             vrrpv3._CHECKSUM_OFFSET, vrrp_.checksum)
+        return buf
+
+    def is_valid(self):
+        return (self.version == VRRP_VERSION_V3 and
+                self.type == VRRP_TYPE_ADVERTISEMENT and
+                VRRP_VRID_MIN <= self.vrid and self.vrid <= VRRP_VRID_MAX and
+                VRRP_PRIORITY_MIN <= self.vrid and
+                self.vrid <= VRRP_PRIORITY_MAX and
+                VRRP_V3_MAX_ADVER_INT_MIN <= self.max_adver_int and
+                self.max_adver_int <= VRRP_V3_MAX_ADVER_INT_MAX and
+                self.count_ip == len(self.ip_addresses))
+
+
+ipv4.ipv4.register_packet_type(vrrp, inet.IPPROTO_VRRP)
+ipv6.ipv6.register_packet_type(vrrp, inet.IPPROTO_VRRP)
-- 
1.7.10.4


------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to