backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / igmp.py
1 # Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
2 #
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
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
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
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """
17 Internet Group Management Protocol(IGMP) packet parser/serializer
18
19 [RFC 1112] IGMP v1 format::
20
21     0                   1                   2                   3
22     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
23    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24    |Version| Type  |    Unused     |           Checksum            |
25    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26    |                         Group Address                         |
27    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28
29 [RFC 2236] IGMP v2 format::
30
31     0                   1                   2                   3
32     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
33    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34    |      Type     | Max Resp Time |           Checksum            |
35    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36    |                         Group Address                         |
37    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38
39 [RFC 3376] IGMP v3 Membership Query format::
40
41     0                   1                   2                   3
42     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
43    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44    |  Type = 0x11  | Max Resp Code |           Checksum            |
45    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46    |                         Group Address                         |
47    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48    | Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
49    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50    |                       Source Address [1]                      |
51    +-                                                             -+
52    |                       Source Address [2]                      |
53    +-                              .                              -+
54    .                               .                               .
55    .                               .                               .
56    +-                                                             -+
57    |                       Source Address [N]                      |
58    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59
60 IGMP v3 Membership Report format::
61
62     0                   1                   2                   3
63     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
64    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65    |  Type = 0x22  |    Reserved   |           Checksum            |
66    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67    |           Reserved            |  Number of Group Records (M)  |
68    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69    |                                                               |
70    .                                                               .
71    .                        Group Record [1]                       .
72    .                                                               .
73    |                                                               |
74    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75    |                                                               |
76    .                                                               .
77    .                        Group Record [2]                       .
78    .                                                               .
79    |                                                               |
80    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81    |                               .                               |
82    .                               .                               .
83    |                               .                               |
84    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85    |                                                               |
86    .                                                               .
87    .                        Group Record [M]                       .
88    .                                                               .
89    |                                                               |
90    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91
92 Where each Group Record has the following internal format::
93
94    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95    |  Record Type  |  Aux Data Len |     Number of Sources (N)     |
96    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97    |                       Multicast Address                       |
98    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99    |                       Source Address [1]                      |
100    +-                                                             -+
101    |                       Source Address [2]                      |
102    +-                                                             -+
103    .                               .                               .
104    .                               .                               .
105    .                               .                               .
106    +-                                                             -+
107    |                       Source Address [N]                      |
108    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109    |                                                               |
110    .                                                               .
111    .                         Auxiliary Data                        .
112    .                                                               .
113    |                                                               |
114    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 """
116
117 import six
118 import struct
119 from math import trunc
120
121 from ryu.lib import addrconv
122 from ryu.lib import stringify
123 from ryu.lib.packet import packet_base
124 from ryu.lib.packet import packet_utils
125
126
127 IGMP_TYPE_QUERY = 0x11
128 IGMP_TYPE_REPORT_V1 = 0x12
129 IGMP_TYPE_REPORT_V2 = 0x16
130 IGMP_TYPE_LEAVE = 0x17
131 IGMP_TYPE_REPORT_V3 = 0x22
132
133 QUERY_RESPONSE_INTERVAL = 10.0
134 LAST_MEMBER_QUERY_INTERVAL = 1.0
135
136 MULTICAST_IP_ALL_HOST = '224.0.0.1'
137 MULTICAST_MAC_ALL_HOST = '01:00:5e:00:00:01'
138
139 # for types of IGMPv3 Report Group Records
140 MODE_IS_INCLUDE = 1
141 MODE_IS_EXCLUDE = 2
142 CHANGE_TO_INCLUDE_MODE = 3
143 CHANGE_TO_EXCLUDE_MODE = 4
144 ALLOW_NEW_SOURCES = 5
145 BLOCK_OLD_SOURCES = 6
146
147
148 class igmp(packet_base.PacketBase):
149     """
150     Internet Group Management Protocol(IGMP, RFC 1112, RFC 2236)
151     header encoder/decoder class.
152
153     http://www.ietf.org/rfc/rfc1112.txt
154
155     http://www.ietf.org/rfc/rfc2236.txt
156
157     An instance has the following attributes at least.
158     Most of them are same to the on-wire counterparts but in host byte
159     order.
160     __init__ takes the corresponding args in this order.
161
162     =============== ====================================================
163     Attribute       Description
164     =============== ====================================================
165     msgtype         a message type for v2, or a combination of
166                     version and a message type for v1.
167     maxresp         max response time in unit of 1/10 second. it is
168                     meaningful only in Query Message.
169     csum            a check sum value. 0 means automatically-calculate
170                     when encoding.
171     address         a group address value.
172     =============== ====================================================
173     """
174     _PACK_STR = '!BBH4s'
175     _MIN_LEN = struct.calcsize(_PACK_STR)
176     _TYPE = {
177         'ascii': [
178             'address'
179         ]
180     }
181
182     def __init__(self, msgtype=IGMP_TYPE_QUERY, maxresp=0, csum=0,
183                  address='0.0.0.0'):
184         super(igmp, self).__init__()
185         self.msgtype = msgtype
186         self.maxresp = maxresp
187         self.csum = csum
188         self.address = address
189
190     @classmethod
191     def parser(cls, buf):
192         assert cls._MIN_LEN <= len(buf)
193         (msgtype, ) = struct.unpack_from('!B', buf)
194         if (IGMP_TYPE_QUERY == msgtype and
195                 igmpv3_query.MIN_LEN <= len(buf)):
196             (instance, subclass, rest,) = igmpv3_query.parser(buf)
197         elif IGMP_TYPE_REPORT_V3 == msgtype:
198             (instance, subclass, rest,) = igmpv3_report.parser(buf)
199         else:
200             (msgtype, maxresp, csum, address
201              ) = struct.unpack_from(cls._PACK_STR, buf)
202             instance = cls(msgtype, maxresp, csum,
203                            addrconv.ipv4.bin_to_text(address))
204             subclass = None
205             rest = buf[cls._MIN_LEN:]
206         return instance, subclass, rest
207
208     def serialize(self, payload, prev):
209         hdr = bytearray(struct.pack(self._PACK_STR, self.msgtype,
210                                     trunc(self.maxresp), self.csum,
211                                     addrconv.ipv4.text_to_bin(self.address)))
212
213         if self.csum == 0:
214             self.csum = packet_utils.checksum(hdr)
215             struct.pack_into('!H', hdr, 2, self.csum)
216
217         return hdr
218
219
220 class igmpv3_query(igmp):
221     """
222     Internet Group Management Protocol(IGMP, RFC 3376)
223     Membership Query message encoder/decoder class.
224
225     http://www.ietf.org/rfc/rfc3376.txt
226
227     An instance has the following attributes at least.
228     Most of them are same to the on-wire counterparts but in host byte
229     order.
230     __init__ takes the corresponding args in this order.
231
232     .. tabularcolumns:: |l|L|
233
234     =============== ====================================================
235     Attribute       Description
236     =============== ====================================================
237     msgtype         a message type for v3.
238     maxresp         max response time in unit of 1/10 second.
239     csum            a check sum value. 0 means automatically-calculate
240                     when encoding.
241     address         a group address value.
242     s_flg           when set to 1, routers suppress the timer process.
243     qrv             robustness variable for a querier.
244     qqic            an interval time for a querier in unit of seconds.
245     num             a number of the multicast servers.
246     srcs            a list of IPv4 addresses of the multicast servers.
247     =============== ====================================================
248     """
249
250     _PACK_STR = '!BBH4sBBH'
251     _MIN_LEN = struct.calcsize(_PACK_STR)
252     MIN_LEN = _MIN_LEN
253     _TYPE = {
254         'ascii': [
255             'address'
256         ],
257         'asciilist': [
258             'srcs'
259         ]
260     }
261
262     def __init__(self, msgtype=IGMP_TYPE_QUERY, maxresp=100, csum=0,
263                  address='0.0.0.0', s_flg=0, qrv=2, qqic=0, num=0,
264                  srcs=None):
265         super(igmpv3_query, self).__init__(
266             msgtype, maxresp, csum, address)
267         self.s_flg = s_flg
268         self.qrv = qrv
269         self.qqic = qqic
270         self.num = num
271         srcs = srcs or []
272         assert isinstance(srcs, list)
273         for src in srcs:
274             assert isinstance(src, str)
275         self.srcs = srcs
276
277     @classmethod
278     def parser(cls, buf):
279         (msgtype, maxresp, csum, address, s_qrv, qqic, num
280          ) = struct.unpack_from(cls._PACK_STR, buf)
281         s_flg = (s_qrv >> 3) & 0b1
282         qrv = s_qrv & 0b111
283         offset = cls._MIN_LEN
284         srcs = []
285         while 0 < len(buf[offset:]) and num > len(srcs):
286             assert 4 <= len(buf[offset:])
287             (src, ) = struct.unpack_from('4s', buf, offset)
288             srcs.append(addrconv.ipv4.bin_to_text(src))
289             offset += 4
290         assert num == len(srcs)
291         return (cls(msgtype, maxresp, csum,
292                     addrconv.ipv4.bin_to_text(address), s_flg, qrv,
293                     qqic, num, srcs),
294                 None,
295                 buf[offset:])
296
297     def serialize(self, payload, prev):
298         s_qrv = self.s_flg << 3 | self.qrv
299         buf = bytearray(struct.pack(self._PACK_STR, self.msgtype,
300                                     trunc(self.maxresp), self.csum,
301                                     addrconv.ipv4.text_to_bin(self.address),
302                                     s_qrv, trunc(self.qqic), self.num))
303         for src in self.srcs:
304             buf.extend(struct.pack('4s', addrconv.ipv4.text_to_bin(src)))
305         if 0 == self.num:
306             self.num = len(self.srcs)
307             struct.pack_into('!H', buf, 10, self.num)
308         if 0 == self.csum:
309             self.csum = packet_utils.checksum(buf)
310             struct.pack_into('!H', buf, 2, self.csum)
311         return six.binary_type(buf)
312
313     def __len__(self):
314         return self._MIN_LEN + len(self.srcs) * 4
315
316
317 class igmpv3_report(igmp):
318     """
319     Internet Group Management Protocol(IGMP, RFC 3376)
320     Membership Report message encoder/decoder class.
321
322     http://www.ietf.org/rfc/rfc3376.txt
323
324     An instance has the following attributes at least.
325     Most of them are same to the on-wire counterparts but in host byte
326     order.
327     __init__ takes the corresponding args in this order.
328
329     .. tabularcolumns:: |l|L|
330
331     =============== ====================================================
332     Attribute       Description
333     =============== ====================================================
334     msgtype         a message type for v3.
335     csum            a check sum value. 0 means automatically-calculate
336                     when encoding.
337     record_num      a number of the group records.
338     records         a list of ryu.lib.packet.igmp.igmpv3_report_group.
339                     None if no records.
340     =============== ====================================================
341     """
342
343     _PACK_STR = '!BxH2xH'
344     _MIN_LEN = struct.calcsize(_PACK_STR)
345     _class_prefixes = ['igmpv3_report_group']
346
347     def __init__(self, msgtype=IGMP_TYPE_REPORT_V3, csum=0, record_num=0,
348                  records=None):
349         self.msgtype = msgtype
350         self.csum = csum
351         self.record_num = record_num
352         records = records or []
353         assert isinstance(records, list)
354         for record in records:
355             assert isinstance(record, igmpv3_report_group)
356         self.records = records
357
358     @classmethod
359     def parser(cls, buf):
360         (msgtype, csum, record_num
361          ) = struct.unpack_from(cls._PACK_STR, buf)
362         offset = cls._MIN_LEN
363         records = []
364         while 0 < len(buf[offset:]) and record_num > len(records):
365             record = igmpv3_report_group.parser(buf[offset:])
366             records.append(record)
367             offset += len(record)
368         assert record_num == len(records)
369         return (cls(msgtype, csum, record_num, records),
370                 None,
371                 buf[offset:])
372
373     def serialize(self, payload, prev):
374         buf = bytearray(struct.pack(self._PACK_STR, self.msgtype,
375                                     self.csum, self.record_num))
376         for record in self.records:
377             buf.extend(record.serialize())
378         if 0 == self.record_num:
379             self.record_num = len(self.records)
380             struct.pack_into('!H', buf, 6, self.record_num)
381         if 0 == self.csum:
382             self.csum = packet_utils.checksum(buf)
383             struct.pack_into('!H', buf, 2, self.csum)
384         return six.binary_type(buf)
385
386     def __len__(self):
387         records_len = 0
388         for record in self.records:
389             records_len += len(record)
390         return self._MIN_LEN + records_len
391
392
393 class igmpv3_report_group(stringify.StringifyMixin):
394     r"""
395     Internet Group Management Protocol(IGMP, RFC 3376)
396     Membership Report Group Record message encoder/decoder class.
397
398     http://www.ietf.org/rfc/rfc3376.txt
399
400     This is used with ryu.lib.packet.igmp.igmpv3_report.
401
402     An instance has the following attributes at least.
403     Most of them are same to the on-wire counterparts but in host byte
404     order.
405     __init__ takes the corresponding args in this order.
406
407     .. tabularcolumns:: |l|L|
408
409     =============== ====================================================
410     Attribute       Description
411     =============== ====================================================
412     type\_          a group record type for v3.
413     aux_len         the length of the auxiliary data.
414     num             a number of the multicast servers.
415     address         a group address value.
416     srcs            a list of IPv4 addresses of the multicast servers.
417     aux             the auxiliary data.
418     =============== ====================================================
419     """
420     _PACK_STR = '!BBH4s'
421     _MIN_LEN = struct.calcsize(_PACK_STR)
422     _TYPE = {
423         'ascii': [
424             'address'
425         ],
426         'asciilist': [
427             'srcs'
428         ]
429     }
430
431     def __init__(self, type_=0, aux_len=0, num=0, address='0.0.0.0',
432                  srcs=None, aux=None):
433         self.type_ = type_
434         self.aux_len = aux_len
435         self.num = num
436         self.address = address
437         srcs = srcs or []
438         assert isinstance(srcs, list)
439         for src in srcs:
440             assert isinstance(src, str)
441         self.srcs = srcs
442         self.aux = aux
443
444     @classmethod
445     def parser(cls, buf):
446         (type_, aux_len, num, address
447          ) = struct.unpack_from(cls._PACK_STR, buf)
448         offset = cls._MIN_LEN
449         srcs = []
450         while 0 < len(buf[offset:]) and num > len(srcs):
451             assert 4 <= len(buf[offset:])
452             (src, ) = struct.unpack_from('4s', buf, offset)
453             srcs.append(addrconv.ipv4.bin_to_text(src))
454             offset += 4
455         assert num == len(srcs)
456         aux = None
457         if aux_len:
458             (aux, ) = struct.unpack_from('%ds' % (aux_len * 4), buf, offset)
459         return cls(type_, aux_len, num,
460                    addrconv.ipv4.bin_to_text(address), srcs, aux)
461
462     def serialize(self):
463         buf = bytearray(struct.pack(self._PACK_STR, self.type_,
464                                     self.aux_len, self.num,
465                                     addrconv.ipv4.text_to_bin(self.address)))
466         for src in self.srcs:
467             buf.extend(struct.pack('4s', addrconv.ipv4.text_to_bin(src)))
468         if 0 == self.num:
469             self.num = len(self.srcs)
470             struct.pack_into('!H', buf, 2, self.num)
471         if self.aux is not None:
472             mod = len(self.aux) % 4
473             if mod:
474                 self.aux += bytearray(4 - mod)
475                 self.aux = six.binary_type(self.aux)
476             buf.extend(self.aux)
477             if 0 == self.aux_len:
478                 self.aux_len = len(self.aux) // 4
479                 struct.pack_into('!B', buf, 1, self.aux_len)
480         return six.binary_type(buf)
481
482     def __len__(self):
483         return self._MIN_LEN + len(self.srcs) * 4 + self.aux_len * 4