# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013 Isaku Yamahata # # 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 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 from ryu.lib import addrconv # IPv4 # the LSB 8 bits is used for VRID VRRP_IPV4_SRC_MAC_ADDRESS_FMT = '00:00:5E:00:01:%02x' VRRP_IPV4_DST_MAC_ADDRESS = '01:00:5E:00:00:12' VRRP_IPV4_DST_ADDRESS = '224.0.0.18' VRRP_IPV4_TTL = 255 def vrrp_ipv4_src_mac_address(vrid): return VRRP_IPV4_SRC_MAC_ADDRESS_FMT % vrid # IPv6 # the LSB 8 bits is used for VRID VRRP_IPV6_SRC_MAC_ADDRESS_FMT = '00:00:5E:00:02:%02x' VRRP_IPV6_DST_MAC_ADDRESS = '33:33:00:00:00:12' VRRP_IPV6_DST_ADDRESS = 'ff02::12' VRRP_IPV6_HOP_LIMIT = 255 def vrrp_ipv6_src_mac_address(vrid): return VRRP_IPV6_SRC_MAC_ADDRESS_FMT % 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): assert type(ip_address) == str try: addrconv.ipv4.text_to_bin(ip_address) except: addrconv.ipv6.text_to_bin(ip_address) # sanity return True return False def ip_text_to_bin(ip_text): if is_ipv6(ip_text): return addrconv.ipv6.text_to_bin(ip_text) else: return addrconv.ipv4.text_to_bin(ip_text) # This is used for master selection def ip_address_lt(ip1, ip2): return ip_text_to_bin(ip1) < ip_text_to_bin(ip2) class vrrp(packet_base.PacketBase): """The base class for VRRPv2 (RFC 3768) and VRRPv3 (RFC 5798) header encoder/decoder classes. Unlike other ryu.lib.packet.packet_base.PacketBase derived classes, This class should not be directly instantiated by user. An instance has the following attributes at least. Most of them are same to the on-wire counterparts but in host byte order. ============== ==================== Attribute Description ============== ==================== version Version type Type vrid Virtual Rtr ID (VRID) priority Priority count_ip Count IPvX Addr. \ Calculated automatically when encoding. max_adver_int Maximum Advertisement Interval (Max Adver Int) checksum Checksum. \ Calculated automatically when encoding. ip_addresses IPvX Address(es). A python list of IP addresses. auth_type Authentication Type (only for VRRPv2) auth_data Authentication Data (only for VRRPv2) ============== ==================== """ _VERSION_PACK_STR = '!B' _IPV4_ADDRESS_PACK_STR_RAW = '4s' _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_): may_ip = None may_vrrp = None idx = 0 for protocol in packet_: if isinstance(protocol, ipv4.ipv4) or isinstance(protocol, ipv6.ipv6): may_ip = protocol try: if isinstance(packet_.protocols[idx + 1], vrrp): may_vrrp = packet_.protocols[idx + 1] finally: break idx += 1 if may_ip and may_vrrp: return may_ip, may_vrrp else: return None, None @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.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): """Prepare a VRRP packet. Returns a newly created ryu.lib.packet.packet.Packet object with appropriate protocol header objects added by add_protocol(). It's caller's responsibility to serialize(). The serialized packet would looks like the ones described in the following sections. * RFC 3768 5.1. VRRP Packet Format * RFC 5798 5.1. VRRP Packet Format ================== ==================== Argument Description ================== ==================== primary_ip_address Source IP address vlan_id VLAN ID. None for no VLAN. ================== ==================== """ if self.is_ipv6: traffic_class = 0xc0 # set tos to internetwork control flow_label = 0 payload_length = ipv6.ipv6._MIN_LEN + len(self) # 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 cls is 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): """VRRPv2 (RFC 3768) header encoder/decoder class. Unlike other ryu.lib.packet.packet_base.PacketBase derived classes, *create* method should be used to instantiate an object of this class. """ _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): """Unlike other ryu.lib.packet.packet_base.PacketBase derived classes, this method should be used to instantiate an object of this class. This method's arguments are same as ryu.lib.packet.vrrp.vrrp object's attributes of the same name. (except that *type_* corresponds to *type* attribute.) """ 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_bin = struct.unpack_from(ip_addresses_pack_str, buf, offset) ip_addresses = map(lambda x: addrconv.ipv4.bin_to_text(x), ip_addresses_bin) offset += struct.calcsize(ip_addresses_pack_str) auth_data = struct.unpack_from(cls._AUTH_DATA_PACK_STR, buf, offset) msg = cls(version, type_, vrid, priority, count_ip, adver_int, checksum, ip_addresses, auth_type, auth_data) return msg, None, buf[len(msg):] @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, *map(lambda x: addrconv.ipv4.text_to_bin(x), 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.priority and self.priority <= 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): """VRRPv3 (RFC 5798) header encoder/decoder class. Unlike other ryu.lib.packet.packet_base.PacketBase derived classes, *create* method should be used to instantiate an object of this class. """ _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, len(self), vrrp_buf) == 0 @staticmethod def create(type_, vrid, priority, max_adver_int, ip_addresses): """Unlike other ryu.lib.packet.packet_base.PacketBase derived classes, this method should be used to instantiate an object of this class. This method's arguments are same as ryu.lib.packet.vrrp.vrrp object's attributes of the same name. (except that *type_* corresponds to *type* attribute.) """ 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 conv = addrconv.ipv4.bin_to_text elif address_len == cls._IPV6_ADDRESS_LEN: pack_str = '!' + cls._IPV6_ADDRESS_PACK_STR_RAW * count_ip conv = addrconv.ipv6.bin_to_text else: raise ValueError( 'unknown address version address_len %d count_ip %d' % ( address_len, count_ip)) ip_addresses_bin = struct.unpack_from(pack_str, buf, offset) ip_addresses = map(lambda x: conv(x), ip_addresses_bin) msg = cls(version, type_, vrid, priority, count_ip, max_adver_int, checksum, ip_addresses) return msg, None, buf[len(msg):] @staticmethod def serialize_static(vrrp_, prev): if isinstance(prev, ipv4.ipv4): assert type(vrrp_.ip_addresses[0]) == str conv = addrconv.ipv4.text_to_bin ip_address_pack_raw = vrrpv3._IPV4_ADDRESS_PACK_STR_RAW elif isinstance(prev, ipv6.ipv6): assert type(vrrp_.ip_addresses[0]) == str conv = addrconv.ipv6.text_to_bin 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, *map(lambda x: conv(x), 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.priority and self.priority <= 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)