1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
23 from . import packet_base
24 from . import packet_utils
25 from ryu.lib import addrconv
26 from ryu.lib import stringify
28 ICMPV6_DST_UNREACH = 1 # dest unreachable, codes:
29 ICMPV6_PACKET_TOO_BIG = 2 # packet too big
30 ICMPV6_TIME_EXCEEDED = 3 # time exceeded, code:
31 ICMPV6_PARAM_PROB = 4 # ip6 header bad
33 ICMPV6_ECHO_REQUEST = 128 # echo service
34 ICMPV6_ECHO_REPLY = 129 # echo reply
35 MLD_LISTENER_QUERY = 130 # multicast listener query
36 MLD_LISTENER_REPOR = 131 # multicast listener report
37 MLD_LISTENER_DONE = 132 # multicast listener done
38 MLDV2_LISTENER_REPORT = 143 # multicast listern report (v2)
41 ICMPV6_MEMBERSHIP_QUERY = 130 # group membership query
42 ICMPV6_MEMBERSHIP_REPORT = 131 # group membership report
43 ICMPV6_MEMBERSHIP_REDUCTION = 132 # group membership termination
45 ND_ROUTER_SOLICIT = 133 # router solicitation
46 ND_ROUTER_ADVERT = 134 # router advertisment
47 ND_NEIGHBOR_SOLICIT = 135 # neighbor solicitation
48 ND_NEIGHBOR_ADVERT = 136 # neighbor advertisment
49 ND_REDIREC = 137 # redirect
51 ICMPV6_ROUTER_RENUMBERING = 138 # router renumbering
53 ICMPV6_WRUREQUEST = 139 # who are you request
54 ICMPV6_WRUREPLY = 140 # who are you reply
55 ICMPV6_FQDN_QUERY = 139 # FQDN query
56 ICMPV6_FQDN_REPLY = 140 # FQDN reply
57 ICMPV6_NI_QUERY = 139 # node information request
58 ICMPV6_NI_REPLY = 140 # node information reply
62 # ND_OPTIONS from RFC 4861
63 ND_OPTION_SLA = 1 # Source Link-Layer Address
64 ND_OPTION_TLA = 2 # Target Link-Layer Address
65 ND_OPTION_PI = 3 # Prefix Information
66 ND_OPTION_RH = 4 # Redirected Header
67 ND_OPTION_MTU = 5 # MTU
71 CHANGE_TO_INCLUDE_MODE = 3
72 CHANGE_TO_EXCLUDE_MODE = 4
77 class icmpv6(packet_base.PacketBase):
78 r"""ICMPv6 (RFC 2463) header encoder/decoder class.
80 An instance has the following attributes at least.
81 Most of them are same to the on-wire counterparts but in host byte order.
82 __init__ takes the corresponding args in this order.
84 .. tabularcolumns:: |l|p{35em}|
86 ============== ====================
88 ============== ====================
92 (0 means automatically-calculate when encoding)
95 ryu.lib.packet.icmpv6.echo object, \
96 ryu.lib.packet.icmpv6.nd_neighbor object, \
97 ryu.lib.packet.icmpv6.nd_router_solicit object, \
98 ryu.lib.packet.icmpv6.nd_router_advert object, \
99 ryu.lib.packet.icmpv6.mld object, \
101 ============== ====================
104 _MIN_LEN = struct.calcsize(_PACK_STR)
108 def register_icmpv6_type(*args):
109 def _register_icmpv6_type(cls):
111 icmpv6._ICMPV6_TYPES[type_] = cls
113 return _register_icmpv6_type
115 def __init__(self, type_=0, code=0, csum=0, data=b''):
116 super(icmpv6, self).__init__()
123 def parser(cls, buf):
124 (type_, code, csum) = struct.unpack_from(cls._PACK_STR, buf)
125 msg = cls(type_, code, csum)
126 offset = cls._MIN_LEN
127 if len(buf) > offset:
128 cls_ = cls._ICMPV6_TYPES.get(type_, None)
130 msg.data = cls_.parser(buf, offset)
132 msg.data = buf[offset:]
134 return msg, None, None
136 def serialize(self, payload, prev):
137 hdr = bytearray(struct.pack(icmpv6._PACK_STR, self.type_,
138 self.code, self.csum))
141 if self.type_ in icmpv6._ICMPV6_TYPES:
142 assert isinstance(self.data, _ICMPv6Payload)
143 hdr += self.data.serialize()
147 self.csum = packet_utils.checksum_ip(prev, len(hdr), hdr + payload)
148 struct.pack_into('!H', hdr, 2, self.csum)
153 return self._MIN_LEN + len(self.data)
156 @six.add_metaclass(abc.ABCMeta)
157 class _ICMPv6Payload(stringify.StringifyMixin):
159 Base class for the payload of ICMPv6 packet.
163 @icmpv6.register_icmpv6_type(ND_NEIGHBOR_SOLICIT, ND_NEIGHBOR_ADVERT)
164 class nd_neighbor(_ICMPv6Payload):
165 """ICMPv6 sub encoder/decoder class for Neighbor Solicitation and
166 Neighbor Advertisement messages. (RFC 4861)
168 This is used with ryu.lib.packet.icmpv6.icmpv6.
170 An instance has the following attributes at least.
171 Most of them are same to the on-wire counterparts but in host byte order.
172 __init__ takes the corresponding args in this order.
174 .. tabularcolumns:: |l|p{35em}|
176 ============== ====================
177 Attribute Description
178 ============== ====================
179 res R,S,O Flags for Neighbor Advertisement. \
180 The 3 MSBs of "Reserved" field for Neighbor Solicitation.
182 option a derived object of ryu.lib.packet.icmpv6.nd_option \
183 or a bytearray. None if no options.
184 ============== ====================
188 _MIN_LEN = struct.calcsize(_PACK_STR)
189 _ND_OPTION_TYPES = {}
197 def register_nd_option_type(*args):
198 def _register_nd_option_type(cls):
199 nd_neighbor._ND_OPTION_TYPES[cls.option_type()] = cls
201 return _register_nd_option_type(args[0])
203 def __init__(self, res=0, dst='::', option=None):
209 def parser(cls, buf, offset):
210 (res, dst) = struct.unpack_from(cls._PACK_STR, buf, offset)
211 offset += cls._MIN_LEN
213 if len(buf) > offset:
214 (type_, length) = struct.unpack_from('!BB', buf, offset)
216 raise struct.error('Invalid length: {len}'.format(len=length))
217 cls_ = cls._ND_OPTION_TYPES.get(type_)
219 option = cls_.parser(buf, offset)
221 option = buf[offset:]
222 msg = cls(res >> 29, addrconv.ipv6.bin_to_text(dst), option)
227 hdr = bytearray(struct.pack(
228 nd_neighbor._PACK_STR, res,
229 addrconv.ipv6.text_to_bin(self.dst)))
230 if self.option is not None:
231 if isinstance(self.option, nd_option):
232 hdr.extend(self.option.serialize())
234 hdr.extend(self.option)
235 return six.binary_type(hdr)
238 length = self._MIN_LEN
239 if self.option is not None:
240 length += len(self.option)
244 @icmpv6.register_icmpv6_type(ND_ROUTER_SOLICIT)
245 class nd_router_solicit(_ICMPv6Payload):
246 """ICMPv6 sub encoder/decoder class for Router Solicitation messages.
249 This is used with ryu.lib.packet.icmpv6.icmpv6.
251 An instance has the following attributes at least.
252 Most of them are same to the on-wire counterparts but in host byte order.
253 __init__ takes the corresponding args in this order.
255 .. tabularcolumns:: |l|p{35em}|
257 ============== ====================
258 Attribute Description
259 ============== ====================
260 res This field is unused. It MUST be initialized to zero.
261 option a derived object of ryu.lib.packet.icmpv6.nd_option \
262 or a bytearray. None if no options.
263 ============== ====================
267 _MIN_LEN = struct.calcsize(_PACK_STR)
268 _ND_OPTION_TYPES = {}
271 def register_nd_option_type(*args):
272 def _register_nd_option_type(cls):
273 nd_router_solicit._ND_OPTION_TYPES[cls.option_type()] = cls
275 return _register_nd_option_type(args[0])
277 def __init__(self, res=0, option=None):
282 def parser(cls, buf, offset):
283 (res, ) = struct.unpack_from(cls._PACK_STR, buf, offset)
284 offset += cls._MIN_LEN
286 if len(buf) > offset:
287 (type_, length) = struct.unpack_from('!BB', buf, offset)
289 raise struct.error('Invalid length: {len}'.format(len=length))
290 cls_ = cls._ND_OPTION_TYPES.get(type_)
292 option = cls_.parser(buf, offset)
294 option = buf[offset:]
295 msg = cls(res, option)
299 hdr = bytearray(struct.pack(
300 nd_router_solicit._PACK_STR, self.res))
301 if self.option is not None:
302 if isinstance(self.option, nd_option):
303 hdr.extend(self.option.serialize())
305 hdr.extend(self.option)
306 return six.binary_type(hdr)
309 length = self._MIN_LEN
310 if self.option is not None:
311 length += len(self.option)
315 @icmpv6.register_icmpv6_type(ND_ROUTER_ADVERT)
316 class nd_router_advert(_ICMPv6Payload):
317 """ICMPv6 sub encoder/decoder class for Router Advertisement messages.
320 This is used with ryu.lib.packet.icmpv6.icmpv6.
322 An instance has the following attributes at least.
323 Most of them are same to the on-wire counterparts but in host byte order.
324 __init__ takes the corresponding args in this order.
326 .. tabularcolumns:: |l|p{35em}|
328 ============== ====================
329 Attribute Description
330 ============== ====================
332 res M,O Flags for Router Advertisement.
333 rou_l Router Lifetime.
334 rea_t Reachable Time.
336 options List of a derived object of \
337 ryu.lib.packet.icmpv6.nd_option or a bytearray. \
339 ============== ====================
343 _MIN_LEN = struct.calcsize(_PACK_STR)
344 _ND_OPTION_TYPES = {}
347 def register_nd_option_type(*args):
348 def _register_nd_option_type(cls):
349 nd_router_advert._ND_OPTION_TYPES[cls.option_type()] = cls
351 return _register_nd_option_type(args[0])
353 def __init__(self, ch_l=0, res=0, rou_l=0, rea_t=0, ret_t=0, options=None):
359 options = options or []
360 assert isinstance(options, list)
361 self.options = options
364 def parser(cls, buf, offset):
365 (ch_l, res, rou_l, rea_t, ret_t
366 ) = struct.unpack_from(cls._PACK_STR, buf, offset)
367 offset += cls._MIN_LEN
369 while len(buf) > offset:
370 (type_, length) = struct.unpack_from('!BB', buf, offset)
372 raise struct.error('Invalid length: {len}'.format(len=length))
373 cls_ = cls._ND_OPTION_TYPES.get(type_)
375 option = cls_.parser(buf, offset)
377 option = buf[offset:offset + (length * 8)]
378 options.append(option)
379 offset += len(option)
380 msg = cls(ch_l, res >> 6, rou_l, rea_t, ret_t, options)
385 hdr = bytearray(struct.pack(
386 nd_router_advert._PACK_STR, self.ch_l, res, self.rou_l,
387 self.rea_t, self.ret_t))
388 for option in self.options:
389 if isinstance(option, nd_option):
390 hdr.extend(option.serialize())
393 return six.binary_type(hdr)
396 length = self._MIN_LEN
397 for option in self.options:
398 length += len(option)
402 @six.add_metaclass(abc.ABCMeta)
403 class nd_option(stringify.StringifyMixin):
406 def option_type(cls):
410 def __init__(self, _type, length):
416 def parser(cls, buf):
427 class nd_option_la(nd_option):
430 _MIN_LEN = struct.calcsize(_PACK_STR)
438 def __init__(self, length, hw_src, data):
439 super(nd_option_la, self).__init__(self.option_type(), length)
444 def parser(cls, buf, offset):
445 (_, length, hw_src) = struct.unpack_from(cls._PACK_STR, buf, offset)
446 msg = cls(length, addrconv.mac.bin_to_text(hw_src))
447 offset += cls._MIN_LEN
448 if len(buf) > offset:
449 msg.data = buf[offset:]
454 buf = bytearray(struct.pack(
455 self._PACK_STR, self.option_type(), self.length,
456 addrconv.mac.text_to_bin(self.hw_src)))
457 if self.data is not None:
458 buf.extend(self.data)
461 buf.extend(bytearray(8 - mod))
463 self.length = len(buf) // 8
464 struct.pack_into('!B', buf, 1, self.length)
465 return six.binary_type(buf)
468 length = self._MIN_LEN
469 if self.data is not None:
470 length += len(self.data)
474 @nd_neighbor.register_nd_option_type
475 @nd_router_solicit.register_nd_option_type
476 @nd_router_advert.register_nd_option_type
477 class nd_option_sla(nd_option_la):
478 """ICMPv6 sub encoder/decoder class for Neighbor discovery
479 Source Link-Layer Address Option. (RFC 4861)
481 This is used with ryu.lib.packet.icmpv6.nd_neighbor,
482 ryu.lib.packet.icmpv6.nd_router_solicit or
483 ryu.lib.packet.icmpv6.nd_router_advert.
485 An instance has the following attributes at least.
486 Most of them are same to the on-wire counterparts but in host byte order.
487 __init__ takes the corresponding args in this order.
489 .. tabularcolumns:: |l|p{35em}|
491 ============== ====================
492 Attribute Description
493 ============== ====================
494 length length of the option. \
495 (0 means automatically-calculate when encoding)
496 hw_src Link-Layer Address. \
497 NOTE: If the address is longer than 6 octets this contains \
498 the first 6 octets in the address. \
499 This implementation assumes the address has at least \
501 data A bytearray which contains the rest of Link-Layer Address \
502 and padding. When encoding a packet, it's user's \
503 responsibility to provide necessary padding for 8-octets \
504 alignment required by the protocol.
505 ============== ====================
509 def option_type(cls):
512 def __init__(self, length=0, hw_src='00:00:00:00:00:00', data=None):
513 super(nd_option_sla, self).__init__(length, hw_src, data)
516 @nd_neighbor.register_nd_option_type
517 class nd_option_tla(nd_option_la):
518 """ICMPv6 sub encoder/decoder class for Neighbor discovery
519 Target Link-Layer Address Option. (RFC 4861)
521 This is used with ryu.lib.packet.icmpv6.nd_neighbor.
523 An instance has the following attributes at least.
524 Most of them are same to the on-wire counterparts but in host byte order.
525 __init__ takes the corresponding args in this order.
527 .. tabularcolumns:: |l|p{35em}|
529 ============== ====================
530 Attribute Description
531 ============== ====================
532 length length of the option. \
533 (0 means automatically-calculate when encoding)
534 hw_src Link-Layer Address. \
535 NOTE: If the address is longer than 6 octets this contains \
536 the first 6 octets in the address. \
537 This implementation assumes the address has at least \
539 data A bytearray which contains the rest of Link-Layer Address \
540 and padding. When encoding a packet, it's user's \
541 responsibility to provide necessary padding for 8-octets \
542 alignment required by the protocol.
543 ============== ====================
547 def option_type(cls):
550 def __init__(self, length=0, hw_src='00:00:00:00:00:00', data=None):
551 super(nd_option_tla, self).__init__(length, hw_src, data)
554 @nd_router_advert.register_nd_option_type
555 class nd_option_pi(nd_option):
556 r"""ICMPv6 sub encoder/decoder class for Neighbor discovery
557 Prefix Information Option. (RFC 4861)
559 This is used with ryu.lib.packet.icmpv6.nd_router_advert.
561 An instance has the following attributes at least.
562 Most of them are same to the on-wire counterparts but in host byte order.
563 __init__ takes the corresponding args in this order.
565 .. tabularcolumns:: |l|p{35em}|
567 ============== ====================
568 Attribute Description
569 ============== ====================
570 length length of the option. \
571 (0 means automatically-calculate when encoding)
573 res1 L,A,R\* Flags for Prefix Information.
574 val_l Valid Lifetime.
575 pre_l Preferred Lifetime.
576 res2 This field is unused. It MUST be initialized to zero.
577 prefix An IP address or a prefix of an IP address.
578 ============== ====================
580 \*R flag is defined in (RFC 3775)
583 _PACK_STR = '!BBBBIII16s'
584 _MIN_LEN = struct.calcsize(_PACK_STR)
592 def option_type(cls):
595 def __init__(self, length=0, pl=0, res1=0, val_l=0, pre_l=0, res2=0,
597 super(nd_option_pi, self).__init__(self.option_type(), length)
606 def parser(cls, buf, offset):
607 (_, length, pl, res1, val_l, pre_l, res2, prefix
608 ) = struct.unpack_from(cls._PACK_STR, buf, offset)
609 msg = cls(length, pl, res1 >> 5, val_l, pre_l, res2,
610 addrconv.ipv6.bin_to_text(prefix))
615 res1 = self.res1 << 5
616 hdr = bytearray(struct.pack(
617 self._PACK_STR, self.option_type(), self.length, self.pl,
618 res1, self.val_l, self.pre_l, self.res2,
619 addrconv.ipv6.text_to_bin(self.prefix)))
621 self.length = len(hdr) // 8
622 struct.pack_into('!B', hdr, 1, self.length)
623 return six.binary_type(hdr)
626 @icmpv6.register_icmpv6_type(ICMPV6_ECHO_REPLY, ICMPV6_ECHO_REQUEST)
627 class echo(_ICMPv6Payload):
628 """ICMPv6 sub encoder/decoder class for Echo Request and Echo Reply
631 This is used with ryu.lib.packet.icmpv6.icmpv6 for
632 ICMPv6 Echo Request and Echo Reply messages.
634 An instance has the following attributes at least.
635 Most of them are same to the on-wire counterparts but in host byte order.
636 __init__ takes the corresponding args in this order.
638 ============== ====================
639 Attribute Description
640 ============== ====================
644 ============== ====================
648 _MIN_LEN = struct.calcsize(_PACK_STR)
650 def __init__(self, id_=0, seq=0, data=None):
656 def parser(cls, buf, offset):
657 (id_, seq) = struct.unpack_from(cls._PACK_STR, buf, offset)
659 offset += cls._MIN_LEN
661 if len(buf) > offset:
662 msg.data = buf[offset:]
667 hdr = bytearray(struct.pack(echo._PACK_STR, self.id,
669 if self.data is not None:
670 hdr += bytearray(self.data)
675 length = self._MIN_LEN
676 if self.data is not None:
677 length += len(self.data)
681 @icmpv6.register_icmpv6_type(
682 MLD_LISTENER_QUERY, MLD_LISTENER_REPOR, MLD_LISTENER_DONE)
683 class mld(_ICMPv6Payload):
684 """ICMPv6 sub encoder/decoder class for MLD Lister Query,
685 MLD Listener Report, and MLD Listener Done messages. (RFC 2710)
687 http://www.ietf.org/rfc/rfc2710.txt
689 This is used with ryu.lib.packet.icmpv6.icmpv6.
691 An instance has the following attributes at least.
692 Most of them are same to the on-wire counterparts but in host byte order.
693 __init__ takes the corresponding args in this order.
695 ============== =========================================
696 Attribute Description
697 ============== =========================================
698 maxresp max response time in millisecond. it is
699 meaningful only in Query Message.
700 address a group address value.
701 ============== =========================================
704 _PACK_STR = '!H2x16s'
705 _MIN_LEN = struct.calcsize(_PACK_STR)
712 def __init__(self, maxresp=0, address='::'):
713 self.maxresp = maxresp
714 self.address = address
717 def parser(cls, buf, offset):
718 if cls._MIN_LEN < len(buf[offset:]):
719 msg = mldv2_query.parser(buf[offset:])
721 (maxresp, address) = struct.unpack_from(
722 cls._PACK_STR, buf, offset)
723 msg = cls(maxresp, addrconv.ipv6.bin_to_text(address))
728 buf = struct.pack(mld._PACK_STR, self.maxresp,
729 addrconv.ipv6.text_to_bin(self.address))
736 class mldv2_query(mld):
738 ICMPv6 sub encoder/decoder class for MLD v2 Lister Query messages.
741 http://www.ietf.org/rfc/rfc3810.txt
743 This is used with ryu.lib.packet.icmpv6.icmpv6.
745 An instance has the following attributes at least.
746 Most of them are same to the on-wire counterparts but in host byte order.
747 __init__ takes the corresponding args in this order.
749 ============== =========================================
750 Attribute Description
751 ============== =========================================
752 maxresp max response time in millisecond. it is
753 meaningful only in Query Message.
754 address a group address value.
755 s_flg when set to 1, routers suppress the timer
757 qrv robustness variable for a querier.
758 qqic an interval time for a querier in unit of
760 num a number of the multicast servers.
761 srcs a list of IPv6 addresses of the multicast
763 ============== =========================================
766 _PACK_STR = '!H2x16sBBH'
767 _MIN_LEN = struct.calcsize(_PACK_STR)
777 def __init__(self, maxresp=0, address='::', s_flg=0, qrv=2,
778 qqic=0, num=0, srcs=None):
779 super(mldv2_query, self).__init__(maxresp, address)
785 assert isinstance(srcs, list)
787 assert isinstance(src, str)
791 def parser(cls, buf):
792 (maxresp, address, s_qrv, qqic, num
793 ) = struct.unpack_from(cls._PACK_STR, buf)
794 s_flg = (s_qrv >> 3) & 0b1
796 offset = cls._MIN_LEN
798 while 0 < len(buf[offset:]) and num > len(srcs):
799 assert 16 <= len(buf[offset:])
800 (src, ) = struct.unpack_from('16s', buf, offset)
801 srcs.append(addrconv.ipv6.bin_to_text(src))
803 assert num == len(srcs)
804 return cls(maxresp, addrconv.ipv6.bin_to_text(address), s_flg,
805 qrv, qqic, num, srcs)
808 s_qrv = self.s_flg << 3 | self.qrv
809 buf = bytearray(struct.pack(self._PACK_STR, self.maxresp,
810 addrconv.ipv6.text_to_bin(self.address), s_qrv,
811 self.qqic, self.num))
812 for src in self.srcs:
813 buf.extend(struct.pack('16s', addrconv.ipv6.text_to_bin(src)))
815 self.num = len(self.srcs)
816 struct.pack_into('!H', buf, 22, self.num)
817 return six.binary_type(buf)
820 return self._MIN_LEN + len(self.srcs) * 16
823 @icmpv6.register_icmpv6_type(MLDV2_LISTENER_REPORT)
824 class mldv2_report(mld):
826 ICMPv6 sub encoder/decoder class for MLD v2 Lister Report messages.
829 http://www.ietf.org/rfc/rfc3810.txt
831 This is used with ryu.lib.packet.icmpv6.icmpv6.
833 An instance has the following attributes at least.
834 Most of them are same to the on-wire counterparts but in host byte order.
835 __init__ takes the corresponding args in this order.
837 ============== =========================================
838 Attribute Description
839 ============== =========================================
840 record_num a number of the group records.
841 records a list of ryu.lib.packet.icmpv6.mldv2_report_group.
843 ============== =========================================
847 _MIN_LEN = struct.calcsize(_PACK_STR)
848 _class_prefixes = ['mldv2_report_group']
850 def __init__(self, record_num=0, records=None):
851 self.record_num = record_num
852 records = records or []
853 assert isinstance(records, list)
854 for record in records:
855 assert isinstance(record, mldv2_report_group)
856 self.records = records
859 def parser(cls, buf, offset):
860 (record_num, ) = struct.unpack_from(cls._PACK_STR, buf, offset)
861 offset += cls._MIN_LEN
863 while 0 < len(buf[offset:]) and record_num > len(records):
864 record = mldv2_report_group.parser(buf[offset:])
865 records.append(record)
866 offset += len(record)
867 assert record_num == len(records)
868 return cls(record_num, records)
871 buf = bytearray(struct.pack(self._PACK_STR, self.record_num))
872 for record in self.records:
873 buf.extend(record.serialize())
874 if 0 == self.record_num:
875 self.record_num = len(self.records)
876 struct.pack_into('!H', buf, 2, self.record_num)
877 return six.binary_type(buf)
881 for record in self.records:
882 records_len += len(record)
883 return self._MIN_LEN + records_len
886 class mldv2_report_group(stringify.StringifyMixin):
888 ICMPv6 sub encoder/decoder class for MLD v2 Lister Report Group
889 Record messages. (RFC 3810)
891 This is used with ryu.lib.packet.icmpv6.mldv2_report.
893 An instance has the following attributes at least.
894 Most of them are same to the on-wire counterparts but in host byte
896 __init__ takes the corresponding args in this order.
898 =============== ====================================================
899 Attribute Description
900 =============== ====================================================
901 type\_ a group record type for v3.
902 aux_len the length of the auxiliary data in 32-bit words.
903 num a number of the multicast servers.
904 address a group address value.
905 srcs a list of IPv6 addresses of the multicast servers.
906 aux the auxiliary data.
907 =============== ====================================================
909 _PACK_STR = '!BBH16s'
910 _MIN_LEN = struct.calcsize(_PACK_STR)
920 def __init__(self, type_=0, aux_len=0, num=0, address='::',
921 srcs=None, aux=None):
923 self.aux_len = aux_len
925 self.address = address
927 assert isinstance(srcs, list)
929 assert isinstance(src, str)
934 def parser(cls, buf):
935 (type_, aux_len, num, address
936 ) = struct.unpack_from(cls._PACK_STR, buf)
937 offset = cls._MIN_LEN
939 while 0 < len(buf[offset:]) and num > len(srcs):
940 assert 16 <= len(buf[offset:])
941 (src, ) = struct.unpack_from('16s', buf, offset)
942 srcs.append(addrconv.ipv6.bin_to_text(src))
944 assert num == len(srcs)
947 (aux, ) = struct.unpack_from('%ds' % (aux_len * 4), buf, offset)
948 msg = cls(type_, aux_len, num, addrconv.ipv6.bin_to_text(address),
953 buf = bytearray(struct.pack(self._PACK_STR, self.type_,
954 self.aux_len, self.num,
955 addrconv.ipv6.text_to_bin(self.address)))
956 for src in self.srcs:
957 buf.extend(struct.pack('16s', addrconv.ipv6.text_to_bin(src)))
959 self.num = len(self.srcs)
960 struct.pack_into('!H', buf, 2, self.num)
961 if self.aux is not None:
962 mod = len(self.aux) % 4
964 self.aux += bytearray(4 - mod)
965 self.aux = six.binary_type(self.aux)
967 if 0 == self.aux_len:
968 self.aux_len = len(self.aux) // 4
969 struct.pack_into('!B', buf, 1, self.aux_len)
970 return six.binary_type(buf)
973 return self._MIN_LEN + len(self.srcs) * 16 + self.aux_len * 4
976 icmpv6.set_classes(icmpv6._ICMPV6_TYPES)
977 nd_neighbor.set_classes(nd_neighbor._ND_OPTION_TYPES)
978 nd_router_solicit.set_classes(nd_router_solicit._ND_OPTION_TYPES)
979 nd_router_advert.set_classes(nd_router_advert._ND_OPTION_TYPES)