backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / vrrp.py
1 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
2 # Copyright (C) 2013 Isaku Yamahata <yamahata at private email ne jp>
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #    http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 """
18 VRRP packet parser/serializer
19
20 [RFC 3768] VRRP v2 packet format::
21
22     0                   1                   2                   3
23     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
24    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25    |Version| Type  | Virtual Rtr ID|   Priority    | Count IP Addrs|
26    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27    |   Auth Type   |   Adver Int   |          Checksum             |
28    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29    |                         IP Address (1)                        |
30    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31    |                            .                                  |
32    |                            .                                  |
33    |                            .                                  |
34    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35    |                         IP Address (n)                        |
36    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37    |                     Authentication Data (1)                   |
38    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39    |                     Authentication Data (2)                   |
40    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41
42
43 [RFC 5798] VRRP v3 packet format::
44
45      0                   1                   2                   3
46      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
47     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48     |                    IPv4 Fields or IPv6 Fields                 |
49    ...                                                             ...
50     |                                                               |
51     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52     |Version| Type  | Virtual Rtr ID|   Priority    |Count IPvX Addr|
53     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54     |(rsvd) |     Max Adver Int     |          Checksum             |
55     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56     |                                                               |
57     +                                                               +
58     |                       IPvX Address(es)                        |
59     +                                                               +
60     +                                                               +
61     +                                                               +
62     +                                                               +
63     |                                                               |
64     +                                                               +
65     |                                                               |
66     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 """
68
69 import struct
70
71 from ryu.lib.packet import ethernet
72 from ryu.lib.packet import ether_types as ether
73 from ryu.lib.packet import in_proto as inet
74 from ryu.lib.packet import ipv4
75 from ryu.lib.packet import ipv6
76 from ryu.lib.packet import packet
77 from ryu.lib.packet import packet_base
78 from ryu.lib.packet import packet_utils
79 from ryu.lib.packet import vlan
80 from ryu.lib import addrconv
81
82
83 # IPv4
84 # the LSB 8 bits is used for VRID
85 VRRP_IPV4_SRC_MAC_ADDRESS_FMT = '00:00:5E:00:01:%02x'
86 VRRP_IPV4_DST_MAC_ADDRESS = '01:00:5E:00:00:12'
87 VRRP_IPV4_DST_ADDRESS = '224.0.0.18'
88 VRRP_IPV4_TTL = 255
89
90
91 def vrrp_ipv4_src_mac_address(vrid):
92     return VRRP_IPV4_SRC_MAC_ADDRESS_FMT % vrid
93
94
95 # IPv6
96 # the LSB 8 bits is used for VRID
97 VRRP_IPV6_SRC_MAC_ADDRESS_FMT = '00:00:5E:00:02:%02x'
98 VRRP_IPV6_DST_MAC_ADDRESS = '33:33:00:00:00:12'
99 VRRP_IPV6_DST_ADDRESS = 'ff02::12'
100 VRRP_IPV6_HOP_LIMIT = 255
101
102
103 def vrrp_ipv6_src_mac_address(vrid):
104     return VRRP_IPV6_SRC_MAC_ADDRESS_FMT % vrid
105
106
107 VRRP_VERSION_SHIFT = 4
108 VRRP_TYPE_MASK = 0xf
109
110
111 def vrrp_from_version_type(version_type):
112     return (version_type >> VRRP_VERSION_SHIFT, version_type & VRRP_TYPE_MASK)
113
114
115 def vrrp_to_version_type(version, type_):
116     return (version << VRRP_VERSION_SHIFT) | type_
117
118
119 # VRRP version
120 VRRP_VERSION_V2 = 2
121 VRRP_VERSION_V3 = 3
122
123 # VRRP type
124 VRRP_TYPE_ADVERTISEMENT = 1
125
126 # VRRP VRID: 0 isn't used
127 VRRP_VRID_MIN = 1
128 VRRP_VRID_MAX = 255
129
130 # VRRP priority
131 VRRP_PRIORITY_MIN = 0
132 VRRP_PRIORITY_MAX = 255
133 VRRP_PRIORITY_RELEASE_RESPONSIBILITY = 0
134 VRRP_PRIORITY_BACKUP_MIN = 1
135 VRRP_PRIORITY_BACKUP_DEFAULT = 100
136 VRRP_PRIORITY_BACKUP_MAX = 254
137 VRRP_PRIORITY_ADDRESS_OWNER = 255
138
139 # VRRP auth type (VRRP v2 only)
140 VRRP_AUTH_NO_AUTH = 0
141 VRRP_AUTH_RESERVED1 = 1
142 VRRP_AUTH_RESERVED2 = 2
143 VRRP_AUTH_DATA1 = 0
144 VRRP_AUTH_DATA2 = 0
145 VRRP_AUTH_DATA = (VRRP_AUTH_DATA1, VRRP_AUTH_DATA2)
146
147 # VRRP Max advertisement interval
148 VRRP_MAX_ADVER_INT_DEFAULT_IN_SEC = 1   # 1 second
149
150 VRRP_V3_MAX_ADVER_INT_MASK = 0xfff      # in centiseconds
151 VRRP_V3_MAX_ADVER_INT_DEFAULT = 100     # = 1 second
152 VRRP_V3_MAX_ADVER_INT_MIN = 1           # don't allow 0
153 VRRP_V3_MAX_ADVER_INT_MAX = 0xfff
154
155 VRRP_V2_MAX_ADVER_INT_MASK = 0xff       # in seconds
156 VRRP_V2_MAX_ADVER_INT_DEFAULT = 1       # 1 second
157 VRRP_V2_MAX_ADVER_INT_MIN = 1           # don't allow 0
158 VRRP_V2_MAX_ADVER_INT_MAX = 0xff
159
160
161 def is_ipv6(ip_address):
162     assert type(ip_address) == str
163     try:
164         addrconv.ipv4.text_to_bin(ip_address)
165     except:
166         addrconv.ipv6.text_to_bin(ip_address)  # sanity
167         return True
168     return False
169
170
171 def ip_text_to_bin(ip_text):
172     if is_ipv6(ip_text):
173         return addrconv.ipv6.text_to_bin(ip_text)
174     else:
175         return addrconv.ipv4.text_to_bin(ip_text)
176
177
178 # This is used for master selection
179 def ip_address_lt(ip1, ip2):
180     return ip_text_to_bin(ip1) < ip_text_to_bin(ip2)
181
182
183 class vrrp(packet_base.PacketBase):
184     """The base class for VRRPv2 (RFC 3768) and VRRPv3 (RFC 5798)
185     header encoder/decoder classes.
186
187     Unlike other ryu.lib.packet.packet_base.PacketBase derived classes,
188     This class should not be directly instantiated by user.
189
190     An instance has the following attributes at least.
191     Most of them are same to the on-wire counterparts but in host byte order.
192
193     ============== ====================
194     Attribute      Description
195     ============== ====================
196     version        Version
197     type           Type
198     vrid           Virtual Rtr ID (VRID)
199     priority       Priority
200     count_ip       Count IPvX Addr. \
201                    Calculated automatically when encoding.
202     max_adver_int  Maximum Advertisement Interval (Max Adver Int)
203     checksum       Checksum. \
204                    Calculated automatically when encoding.
205     ip_addresses   IPvX Address(es).  A python list of IP addresses.
206     auth_type      Authentication Type (only for VRRPv2)
207     auth_data      Authentication Data (only for VRRPv2)
208     ============== ====================
209     """
210
211     _VERSION_PACK_STR = '!B'
212     _IPV4_ADDRESS_PACK_STR_RAW = '4s'
213     _IPV4_ADDRESS_PACK_STR = '!' + _IPV4_ADDRESS_PACK_STR_RAW
214     _IPV4_ADDRESS_LEN = struct.calcsize(_IPV4_ADDRESS_PACK_STR)
215     _IPV6_ADDRESS_LEN = 16
216     _IPV6_ADDRESS_PACK_STR_RAW = '%ds' % _IPV6_ADDRESS_LEN
217     _IPV6_ADDRESS_PACK_STR = '!' + _IPV6_ADDRESS_PACK_STR_RAW
218     _IPV6_ADDRESS_LEN = struct.calcsize(_IPV6_ADDRESS_PACK_STR)
219
220     _VRRP_VERSIONS = {}
221     _SEC_IN_MAX_ADVER_INT_UNIT = {}
222
223     @staticmethod
224     def get_payload(packet_):
225         may_ip = None
226         may_vrrp = None
227
228         idx = 0
229         for protocol in packet_:
230             if isinstance(protocol, ipv4.ipv4) or isinstance(protocol,
231                                                              ipv6.ipv6):
232                 may_ip = protocol
233                 try:
234                     if isinstance(packet_.protocols[idx + 1], vrrp):
235                         may_vrrp = packet_.protocols[idx + 1]
236                 finally:
237                     break
238             idx += 1
239
240         if may_ip and may_vrrp:
241             return may_ip, may_vrrp
242         else:
243             return None, None
244
245     @classmethod
246     def register_vrrp_version(cls, version,
247                               sec_in_max_adver_int_unit):
248         def _register_vrrp_version(cls_):
249             cls._VRRP_VERSIONS[version] = cls_
250             cls._SEC_IN_MAX_ADVER_INT_UNIT[version] = sec_in_max_adver_int_unit
251             return cls_
252         return _register_vrrp_version
253
254     @staticmethod
255     def sec_to_max_adver_int(version, seconds):
256         return int(seconds * vrrp._SEC_IN_MAX_ADVER_INT_UNIT[version])
257
258     @staticmethod
259     def max_adver_int_to_sec(version, max_adver_int):
260         return float(max_adver_int) / vrrp._SEC_IN_MAX_ADVER_INT_UNIT[version]
261
262     def __init__(self, version, type_, vrid, priority, count_ip,
263                  max_adver_int, checksum, ip_addresses,
264
265                  # auth_type/auth_data is for vrrp v2
266                  auth_type=None, auth_data=None):
267         super(vrrp, self).__init__()
268         self.version = version
269         self.type = type_
270         self.vrid = vrid
271         self.priority = priority
272         self.count_ip = count_ip
273         self.max_adver_int = max_adver_int
274
275         self.checksum = checksum
276         self.ip_addresses = ip_addresses
277         assert len(list(ip_addresses)) == self.count_ip
278
279         self.auth_type = auth_type
280         self.auth_data = auth_data
281
282         self._is_ipv6 = is_ipv6(list(self.ip_addresses)[0])
283         self.identification = 0         # used for ipv4 identification
284
285     def checksum_ok(self, ipvx, vrrp_buf):
286         cls_ = self._VRRP_VERSIONS[self.version]
287         return cls_.checksum_ok(self, ipvx, vrrp_buf)
288
289     @property
290     def max_adver_int_in_sec(self):
291         # return seconds of float as time.sleep() accepts such type.
292         return self.max_adver_int_to_sec(self.version, self.max_adver_int)
293
294     @property
295     def is_ipv6(self):
296         return self._is_ipv6
297
298     def __len__(self):
299         cls_ = self._VRRP_VERSIONS[self.version]
300         return cls_.__len__(self)
301
302     @staticmethod
303     def create_version(version, type_, vrid, priority, max_adver_int,
304                        ip_addresses, auth_type=None, auth_data=None):
305         cls_ = vrrp._VRRP_VERSIONS.get(version, None)
306         if not cls_:
307             raise ValueError('unknown VRRP version %d' % version)
308
309         if priority is None:
310             priority = VRRP_PRIORITY_BACKUP_DEFAULT
311         count_ip = len(ip_addresses)
312         if max_adver_int is None:
313             max_adver_int = cls_.sec_to_max_adver_int(
314                 VRRP_MAX_ADVER_INT_DEFAULT_IN_SEC)
315         return cls_(version, type_, vrid, priority, count_ip, max_adver_int,
316                     None, ip_addresses,
317                     auth_type=auth_type, auth_data=auth_data)
318
319     def get_identification(self):
320         self.identification += 1
321         self.identification &= 0xffff
322         if self.identification == 0:
323             self.identification += 1
324             self.identification &= 0xffff
325         return self.identification
326
327     def create_packet(self, primary_ip_address, vlan_id=None):
328         """Prepare a VRRP packet.
329
330         Returns a newly created ryu.lib.packet.packet.Packet object
331         with appropriate protocol header objects added by add_protocol().
332         It's caller's responsibility to serialize().
333         The serialized packet would looks like the ones described in
334         the following sections.
335
336         * RFC 3768 5.1. VRRP Packet Format
337         * RFC 5798 5.1. VRRP Packet Format
338
339         ================== ====================
340         Argument           Description
341         ================== ====================
342         primary_ip_address Source IP address
343         vlan_id            VLAN ID.  None for no VLAN.
344         ================== ====================
345         """
346         if self.is_ipv6:
347             traffic_class = 0xc0        # set tos to internetwork control
348             flow_label = 0
349             payload_length = ipv6.ipv6._MIN_LEN + len(self)     # XXX _MIN_LEN
350             e = ethernet.ethernet(VRRP_IPV6_DST_MAC_ADDRESS,
351                                   vrrp_ipv6_src_mac_address(self.vrid),
352                                   ether.ETH_TYPE_IPV6)
353             ip = ipv6.ipv6(6, traffic_class, flow_label, payload_length,
354                            inet.IPPROTO_VRRP, VRRP_IPV6_HOP_LIMIT,
355                            primary_ip_address, VRRP_IPV6_DST_ADDRESS)
356         else:
357             header_length = ipv4.ipv4._MIN_LEN // 4      # XXX _MIN_LEN
358             total_length = 0
359             tos = 0xc0  # set tos to internetwork control
360             identification = self.get_identification()
361             e = ethernet.ethernet(VRRP_IPV4_DST_MAC_ADDRESS,
362                                   vrrp_ipv4_src_mac_address(self.vrid),
363                                   ether.ETH_TYPE_IP)
364             ip = ipv4.ipv4(4, header_length, tos, total_length, identification,
365                            0, 0, VRRP_IPV4_TTL, inet.IPPROTO_VRRP, 0,
366                            primary_ip_address, VRRP_IPV4_DST_ADDRESS)
367
368         p = packet.Packet()
369         p.add_protocol(e)
370         if vlan_id is not None:
371             vlan_ = vlan.vlan(0, 0, vlan_id, e.ethertype)
372             e.ethertype = ether.ETH_TYPE_8021Q
373             p.add_protocol(vlan_)
374         p.add_protocol(ip)
375         p.add_protocol(self)
376         return p
377
378     @classmethod
379     def parser(cls, buf):
380         (version_type,) = struct.unpack_from(cls._VERSION_PACK_STR, buf)
381         version, _type = vrrp_from_version_type(version_type)
382         cls_ = cls._VRRP_VERSIONS[version]
383         return cls_.parser(buf)
384
385     @staticmethod
386     def serialize_static(vrrp_, prev):
387         # self can be a instance of vrrpv2 or vrrpv3.
388         assert isinstance(vrrp_, vrrp)
389         cls = vrrp._VRRP_VERSIONS[vrrp_.version]
390         return cls.serialize_static(vrrp_, prev)
391
392     def serialize(self, payload, prev):
393         return self.serialize_static(self, prev)
394
395     @staticmethod
396     def is_valid_ttl(ipvx):
397         version = ipvx.version
398         if version == 4:
399             return ipvx.ttl == VRRP_IPV4_TTL
400         if version == 6:
401             return ipvx.hop_limit == VRRP_IPV6_HOP_LIMIT
402
403         raise ValueError('invalid ip version %d' % version)
404
405     def is_valid(self):
406         cls = self._VRRP_VERSIONS.get(self.version, None)
407         if cls is None:
408             return False
409         return cls.is_valid(self)
410
411
412 # max_adver_int is in seconds
413 @vrrp.register_vrrp_version(VRRP_VERSION_V2, 1)
414 class vrrpv2(vrrp):
415     """VRRPv2 (RFC 3768) header encoder/decoder class.
416
417     Unlike other ryu.lib.packet.packet_base.PacketBase derived classes,
418     *create* method should be used to instantiate an object of this class.
419     """
420
421     _PACK_STR = '!BBBBBBH'
422     _MIN_LEN = struct.calcsize(_PACK_STR)
423     _CHECKSUM_PACK_STR = '!H'
424     _CHECKSUM_OFFSET = 6
425     _AUTH_DATA_PACK_STR = '!II'
426     _AUTH_DATA_LEN = struct.calcsize('!II')
427
428     def __len__(self):
429         return (self._MIN_LEN + self._IPV4_ADDRESS_LEN * self.count_ip +
430                 self._AUTH_DATA_LEN)
431
432     def checksum_ok(self, ipvx, vrrp_buf):
433         return packet_utils.checksum(vrrp_buf) == 0
434
435     @staticmethod
436     def create(type_, vrid, priority, max_adver_int, ip_addresses):
437         """Unlike other ryu.lib.packet.packet_base.PacketBase derived classes,
438         this method should be used to instantiate an object of this class.
439
440         This method's arguments are same as ryu.lib.packet.vrrp.vrrp object's
441         attributes of the same name.  (except that *type_* corresponds to
442         *type* attribute.)
443         """
444
445         return vrrp.create_version(VRRP_VERSION_V2, type_, vrid, priority,
446                                    max_adver_int,
447                                    ip_addresses,
448                                    auth_type=VRRP_AUTH_NO_AUTH,
449                                    auth_data=VRRP_AUTH_DATA)
450
451     @staticmethod
452     def _ip_addresses_pack_str(count_ip):
453         return '!' + vrrpv2._IPV4_ADDRESS_PACK_STR_RAW * count_ip
454
455     @classmethod
456     def parser(cls, buf):
457         (version_type, vrid, priority, count_ip, auth_type, adver_int,
458          checksum) = struct.unpack_from(cls._PACK_STR, buf)
459         (version, type_) = vrrp_from_version_type(version_type)
460
461         offset = cls._MIN_LEN
462         ip_addresses_pack_str = cls._ip_addresses_pack_str(count_ip)
463         ip_addresses_bin = struct.unpack_from(ip_addresses_pack_str, buf,
464                                               offset)
465         ip_addresses = [addrconv.ipv4.bin_to_text(x) for x in ip_addresses_bin]
466
467         offset += struct.calcsize(ip_addresses_pack_str)
468         auth_data = struct.unpack_from(cls._AUTH_DATA_PACK_STR, buf, offset)
469
470         msg = cls(version, type_, vrid, priority, count_ip, adver_int,
471                   checksum, ip_addresses, auth_type, auth_data)
472         return msg, None, buf[len(msg):]
473
474     @staticmethod
475     def serialize_static(vrrp_, prev):
476         assert not vrrp_.is_ipv6        # vrrpv2 defines only IPv4
477         ip_addresses_pack_str = vrrpv2._ip_addresses_pack_str(vrrp_.count_ip)
478         ip_addresses_len = struct.calcsize(ip_addresses_pack_str)
479         vrrp_len = vrrpv2._MIN_LEN + ip_addresses_len + vrrpv2._AUTH_DATA_LEN
480
481         checksum = False
482         if vrrp_.checksum is None:
483             checksum = True
484             vrrp_.checksum = 0
485
486         if vrrp_.auth_type is None:
487             vrrp_.auth_type = VRRP_AUTH_NO_AUTH
488         if vrrp_.auth_data is None:
489             vrrp_.auth_data = VRRP_AUTH_DATA
490
491         buf = bytearray(vrrp_len)
492         offset = 0
493         struct.pack_into(vrrpv2._PACK_STR, buf, offset,
494                          vrrp_to_version_type(vrrp_.version, vrrp_.type),
495                          vrrp_.vrid, vrrp_.priority,
496                          vrrp_.count_ip, vrrp_.auth_type, vrrp_.max_adver_int,
497                          vrrp_.checksum)
498         offset += vrrpv2._MIN_LEN
499         struct.pack_into(ip_addresses_pack_str, buf, offset,
500                          *[addrconv.ipv4.text_to_bin(x) for x in vrrp_.ip_addresses])
501         offset += ip_addresses_len
502         struct.pack_into(vrrpv2._AUTH_DATA_PACK_STR, buf, offset,
503                          *vrrp_.auth_data)
504         if checksum:
505             vrrp_.checksum = packet_utils.checksum(buf)
506             struct.pack_into(vrrpv2._CHECKSUM_PACK_STR, buf,
507                              vrrpv2._CHECKSUM_OFFSET, vrrp_.checksum)
508         return buf
509
510     def is_valid(self):
511         return (self.version == VRRP_VERSION_V2 and
512                 self.type == VRRP_TYPE_ADVERTISEMENT and
513                 VRRP_VRID_MIN <= self.vrid and self.vrid <= VRRP_VRID_MAX and
514                 VRRP_PRIORITY_MIN <= self.priority and
515                 self.priority <= VRRP_PRIORITY_MAX and
516                 self.auth_type == VRRP_AUTH_NO_AUTH and
517                 VRRP_V2_MAX_ADVER_INT_MIN <= self.max_adver_int and
518                 self.max_adver_int <= VRRP_V2_MAX_ADVER_INT_MAX and
519                 self.count_ip == len(self.ip_addresses))
520
521
522 # max_adver_int is in centi seconds: 1 second = 100 centiseconds
523 @vrrp.register_vrrp_version(VRRP_VERSION_V3, 100)
524 class vrrpv3(vrrp):
525     """VRRPv3 (RFC 5798) header encoder/decoder class.
526
527     Unlike other ryu.lib.packet.packet_base.PacketBase derived classes,
528     *create* method should be used to instantiate an object of this class.
529     """
530
531     _PACK_STR = '!BBBBHH'
532     _MIN_LEN = struct.calcsize(_PACK_STR)
533     _CHECKSUM_PACK_STR = '!H'
534     _CHECKSUM_OFFSET = 6
535
536     def __len__(self):
537         if self.is_ipv6:
538             address_len = self._IPV6_ADDRESS_LEN
539         else:
540             address_len = self._IPV4_ADDRESS_LEN
541         return self._MIN_LEN + address_len * self.count_ip
542
543     def checksum_ok(self, ipvx, vrrp_buf):
544         # There are two interpretation of IPv4 checksum
545         # include IPv4 pseudo header or not.
546         # http://www.ietf.org/mail-archive/web/vrrp/current/msg01473.html
547         # if not self.is_ipv6:
548         #     return packet_utils.checksum(vrrp_buf) == 0
549         return packet_utils.checksum_ip(ipvx, len(self), vrrp_buf) == 0
550
551     @staticmethod
552     def create(type_, vrid, priority, max_adver_int, ip_addresses):
553         """Unlike other ryu.lib.packet.packet_base.PacketBase derived classes,
554         this method should be used to instantiate an object of this class.
555
556         This method's arguments are same as ryu.lib.packet.vrrp.vrrp object's
557         attributes of the same name.  (except that *type_* corresponds to
558         *type* attribute.)
559         """
560         return vrrp.create_version(VRRP_VERSION_V3, type_, vrid, priority,
561                                    max_adver_int, ip_addresses)
562
563     @classmethod
564     def parser(cls, buf):
565         (version_type, vrid, priority, count_ip, max_adver_int,
566          checksum) = struct.unpack_from(cls._PACK_STR, buf)
567         (version, type_) = vrrp_from_version_type(version_type)
568
569         # _rsvd = (max_adver_int & ~VRRP_V3_MAX_ADVER_INT_MASK) >> 12
570         # asssert _rsvd == 0
571         max_adver_int &= VRRP_V3_MAX_ADVER_INT_MASK
572
573         offset = cls._MIN_LEN
574         address_len = (len(buf) - offset) // count_ip
575         # Address version (IPv4 or IPv6) is determined by network layer
576         # header type.
577         # Unfortunately it isn't available. Guess it by vrrp packet length.
578         if address_len == cls._IPV4_ADDRESS_LEN:
579             pack_str = '!' + cls._IPV4_ADDRESS_PACK_STR_RAW * count_ip
580             conv = addrconv.ipv4.bin_to_text
581         elif address_len == cls._IPV6_ADDRESS_LEN:
582             pack_str = '!' + cls._IPV6_ADDRESS_PACK_STR_RAW * count_ip
583             conv = addrconv.ipv6.bin_to_text
584         else:
585             raise ValueError(
586                 'unknown address version address_len %d count_ip %d' % (
587                     address_len, count_ip))
588
589         ip_addresses_bin = struct.unpack_from(pack_str, buf, offset)
590         ip_addresses = [conv(x) for x in ip_addresses_bin]
591         msg = cls(version, type_, vrid, priority,
592                   count_ip, max_adver_int, checksum, ip_addresses)
593         return msg, None, buf[len(msg):]
594
595     @staticmethod
596     def serialize_static(vrrp_, prev):
597         if isinstance(prev, ipv4.ipv4):
598             assert type(vrrp_.ip_addresses[0]) == str
599             conv = addrconv.ipv4.text_to_bin
600             ip_address_pack_raw = vrrpv3._IPV4_ADDRESS_PACK_STR_RAW
601         elif isinstance(prev, ipv6.ipv6):
602             assert type(vrrp_.ip_addresses[0]) == str
603             conv = addrconv.ipv6.text_to_bin
604             ip_address_pack_raw = vrrpv3._IPV6_ADDRESS_PACK_STR_RAW
605         else:
606             raise ValueError('Unkown network layer %s' % type(prev))
607
608         ip_addresses_pack_str = '!' + ip_address_pack_raw * vrrp_.count_ip
609         ip_addresses_len = struct.calcsize(ip_addresses_pack_str)
610         vrrp_len = vrrpv3._MIN_LEN + ip_addresses_len
611
612         checksum = False
613         if vrrp_.checksum is None:
614             checksum = True
615             vrrp_.checksum = 0
616
617         buf = bytearray(vrrp_len)
618         assert vrrp_.max_adver_int <= VRRP_V3_MAX_ADVER_INT_MASK
619         struct.pack_into(vrrpv3._PACK_STR, buf, 0,
620                          vrrp_to_version_type(vrrp_.version, vrrp_.type),
621                          vrrp_.vrid, vrrp_.priority,
622                          vrrp_.count_ip, vrrp_.max_adver_int, vrrp_.checksum)
623         struct.pack_into(ip_addresses_pack_str, buf, vrrpv3._MIN_LEN,
624                          *[conv(x) for x in vrrp_.ip_addresses])
625
626         if checksum:
627             vrrp_.checksum = packet_utils.checksum_ip(prev, len(buf), buf)
628             struct.pack_into(vrrpv3._CHECKSUM_PACK_STR, buf,
629                              vrrpv3._CHECKSUM_OFFSET, vrrp_.checksum)
630         return buf
631
632     def is_valid(self):
633         return (self.version == VRRP_VERSION_V3 and
634                 self.type == VRRP_TYPE_ADVERTISEMENT and
635                 VRRP_VRID_MIN <= self.vrid and self.vrid <= VRRP_VRID_MAX and
636                 VRRP_PRIORITY_MIN <= self.priority and
637                 self.priority <= VRRP_PRIORITY_MAX and
638                 VRRP_V3_MAX_ADVER_INT_MIN <= self.max_adver_int and
639                 self.max_adver_int <= VRRP_V3_MAX_ADVER_INT_MAX and
640                 self.count_ip == len(self.ip_addresses))
641
642
643 ipv4.ipv4.register_packet_type(vrrp, inet.IPPROTO_VRRP)
644 ipv6.ipv6.register_packet_type(vrrp, inet.IPPROTO_VRRP)