1 # Copyright (C) 2013 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.
17 RFC 2328 OSPF version 2
20 from functools import reduce
26 from ryu.lib import addrconv
27 from ryu.lib.packet import packet_base
28 from ryu.lib.packet import packet_utils
29 from ryu.lib.packet import stream_parser
30 from ryu.lib.stringify import StringifyMixin
31 from ryu.lib import type_desc
34 LOG = logging.getLogger(__name__)
49 OSPF_ASBR_SUMMARY_LSA = 4
50 OSPF_AS_EXTERNAL_LSA = 5
51 OSPF_AS_NSSA_LSA = 7 # RFC 3101
52 OSPF_OPAQUE_LINK_LSA = 9 # RFC 5250
53 OSPF_OPAQUE_AREA_LSA = 10 # RFC 5250
54 OSPF_OPAQUE_AS_LSA = 11 # RFC 5250
56 OSPF_OPTION_T = 1 # Obsolete
57 OSPF_OPTION_E = 1 << 1 # RFC 2328
58 OSPF_OPTION_MC = 1 << 2 # RFC 1584
59 OSPF_OPTION_NP = 1 << 3 # RFC 3101
60 OSPF_OPTION_EA = 1 << 4 # Obsolete
61 OSPF_OPTION_DC = 1 << 5 # RFC 2370
62 OSPF_OPTION_DN = 1 << 7 # RFC 2567
65 LSA_LINK_TYPE_TRANSIT = 2
66 LSA_LINK_TYPE_STUB = 3
69 ROUTER_LSA_BORDER = 0x01 # The router is an ABR
70 ROUTER_LSA_EXTERNAL = 0x02 # The router is an ASBR
71 ROUTER_LSA_VIRTUAL = 0x04 # The router has a VL in this area
72 ROUTER_LSA_NT = 0x10 # The router always translates Type-7
73 ROUTER_LSA_SHORTCUT = 0x20 # Shortcut-ABR specific flag
75 AS_EXTERNAL_METRIC = 0x80
77 OSPF_OPAQUE_TYPE_UNKNOWN = 0
78 OSPF_OPAQUE_TYPE_EXTENDED_PREFIX_LSA = 7
79 OSPF_OPAQUE_TYPE_EXTENDED_LINK_LSA = 8
81 OSPF_EXTENDED_PREFIX_TLV = 1
82 OSPF_EXTENDED_PREFIX_SID_SUBTLV = 2
85 class InvalidChecksum(Exception):
89 class LSAHeader(StringifyMixin):
90 _HDR_PACK_STR = '!HBB4s4sIHH'
91 _HDR_LEN = struct.calcsize(_HDR_PACK_STR)
93 def __init__(self, ls_age=0, options=0, type_=OSPF_UNKNOWN_LSA,
94 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
95 checksum=0, length=0, opaque_type=OSPF_OPAQUE_TYPE_UNKNOWN,
98 self.options = options
100 if self.type_ < OSPF_OPAQUE_LINK_LSA:
103 self.opaque_type = opaque_type
104 self.opaque_id = opaque_id
105 self.adv_router = adv_router
106 self.ls_seqnum = ls_seqnum
107 self.checksum = checksum
111 def parser(cls, buf):
112 if len(buf) < cls._HDR_LEN:
113 raise stream_parser.StreamParser.TooSmallException(
114 '%d < %d' % (len(buf), cls._HDR_LEN))
115 (ls_age, options, type_, id_, adv_router, ls_seqnum, checksum,
116 length,) = struct.unpack_from(cls._HDR_PACK_STR, six.binary_type(buf))
117 adv_router = addrconv.ipv4.bin_to_text(adv_router)
118 rest = buf[cls._HDR_LEN:]
119 lsacls = LSA._lookup_type(type_)
125 "adv_router": adv_router,
126 "ls_seqnum": ls_seqnum,
127 "checksum": checksum,
131 if issubclass(lsacls, OpaqueLSA):
132 (id_,) = struct.unpack_from('!I', id_)
133 value['opaque_type'] = (id_ & 0xff000000) >> 24
134 value['opaque_id'] = (id_ & 0xffffff)
136 value['id_'] = addrconv.ipv4.bin_to_text(id_)
141 if self.type_ < OSPF_OPAQUE_LINK_LSA:
142 id_ = addrconv.ipv4.text_to_bin(self.id_)
144 id_ = (self.opaque_type << 24) + self.opaque_id
145 (id_,) = struct.unpack_from('4s', struct.pack('!I', id_))
147 adv_router = addrconv.ipv4.text_to_bin(self.adv_router)
149 struct.pack(self._HDR_PACK_STR, self.ls_age,
150 self.options, self.type_, id_, adv_router,
151 self.ls_seqnum, self.checksum, self.length))
154 class LSA(type_desc.TypeDisp, StringifyMixin):
155 def __init__(self, ls_age=0, options=0, type_=OSPF_UNKNOWN_LSA,
156 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
157 checksum=0, length=0, opaque_type=OSPF_OPAQUE_TYPE_UNKNOWN,
159 if type_ < OSPF_OPAQUE_LINK_LSA:
160 self.header = LSAHeader(
165 adv_router=adv_router,
168 self.header = LSAHeader(
172 adv_router=adv_router,
174 opaque_type=opaque_type,
177 if not (checksum or length):
178 tail = self.serialize_tail()
179 length = self.header._HDR_LEN + len(tail)
181 head = self.header.serialize()
182 checksum = packet_utils.fletcher_checksum(head[2:], 14)
183 self.header.length = length
184 self.header.checksum = checksum
187 def parser(cls, buf):
188 hdr, rest = LSAHeader.parser(buf)
189 if len(buf) < hdr['length']:
190 raise stream_parser.StreamParser.TooSmallException(
191 '%d < %d' % (len(buf), hdr['length']))
192 # exclude ls_age for checksum calculation
193 csum = packet_utils.fletcher_checksum(buf[2:hdr['length']], 14)
194 if csum != hdr['checksum']:
195 raise InvalidChecksum("header has %d, but calculated value is %d"
196 % (hdr['checksum'], csum))
197 subcls = cls._lookup_type(hdr['type_'])
198 body = rest[:hdr['length'] - LSAHeader._HDR_LEN]
199 rest = rest[hdr['length'] - LSAHeader._HDR_LEN:]
200 if issubclass(subcls, OpaqueLSA):
201 kwargs = subcls.parser(body, hdr['opaque_type'])
203 kwargs = subcls.parser(body)
205 return subcls(**kwargs), subcls, rest
208 tail = self.serialize_tail()
209 self.header.length = self.header._HDR_LEN + len(tail)
210 head = self.header.serialize()
211 # exclude ls_age for checksum calculation
212 csum = packet_utils.fletcher_checksum(head[2:] + tail, 14)
213 self.header.checksum = csum
214 struct.pack_into("!H", head, 16, csum)
217 def serialize_tail(self):
218 # should be implemented in subclass
222 @LSA.register_type(OSPF_ROUTER_LSA)
223 class RouterLSA(LSA):
225 _PACK_LEN = struct.calcsize(_PACK_STR) # 4bytes
227 class Link(StringifyMixin):
228 _PACK_STR = '!4s4sBBH'
229 _PACK_LEN = struct.calcsize(_PACK_STR) # 12bytes
231 def __init__(self, id_='0.0.0.0', data='0.0.0.0',
232 type_=LSA_LINK_TYPE_STUB, tos=0, metric=10):
240 def parser(cls, buf):
241 if len(buf) < cls._PACK_LEN:
242 raise stream_parser.StreamParser.TooSmallException(
243 '%d < %d' % (len(buf), cls._PACK_LEN))
244 link = buf[:cls._PACK_LEN]
245 rest = buf[cls._PACK_LEN:]
246 (id_, data, type_, tos, metric) = \
247 struct.unpack_from(cls._PACK_STR, six.binary_type(link))
248 id_ = addrconv.ipv4.bin_to_text(id_)
249 data = addrconv.ipv4.bin_to_text(data)
250 return cls(id_, data, type_, tos, metric), rest
253 id_ = addrconv.ipv4.text_to_bin(self.id_)
254 data = addrconv.ipv4.text_to_bin(self.data)
256 struct.pack(self._PACK_STR, id_, data, self.type_, self.tos,
259 def __init__(self, ls_age=0, options=0, type_=OSPF_ROUTER_LSA,
260 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
261 checksum=None, length=None, flags=0, links=None):
262 links = links if links else []
265 super(RouterLSA, self).__init__(ls_age, options, type_, id_,
266 adv_router, ls_seqnum, checksum,
270 def parser(cls, buf):
272 hdr = buf[:cls._PACK_LEN]
273 buf = buf[cls._PACK_LEN:]
274 (flags, _, num) = struct.unpack_from(cls._PACK_STR,
275 six.binary_type(hdr))
277 link, buf = cls.Link.parser(buf)
279 assert len(links) == num
285 def serialize_tail(self):
287 struct.pack(self._PACK_STR, self.flags, 0, len(self.links)))
289 return head + reduce(lambda a, b: a + b,
290 (link.serialize() for link in self.links))
295 @LSA.register_type(OSPF_NETWORK_LSA)
296 class NetworkLSA(LSA):
298 _PACK_LEN = struct.calcsize(_PACK_STR)
300 def __init__(self, ls_age=0, options=0, type_=OSPF_NETWORK_LSA,
301 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
302 checksum=None, length=None, mask='0.0.0.0', routers=None):
303 routers = routers if routers else []
305 self.routers = routers
306 super(NetworkLSA, self).__init__(ls_age, options, type_, id_,
307 adv_router, ls_seqnum, checksum,
311 def parser(cls, buf):
312 if len(buf) < cls._PACK_LEN:
313 raise stream_parser.StreamParser.TooSmallException(
314 '%d < %d' % (len(buf), cls._PACK_LEN))
315 binmask = buf[:cls._PACK_LEN]
316 (mask,) = struct.unpack_from(cls._PACK_STR, six.binary_type(binmask))
317 mask = addrconv.ipv4.bin_to_text(mask)
318 buf = buf[cls._PACK_LEN:]
321 binrouter = buf[:cls._PACK_LEN]
322 (router,) = struct.unpack_from(cls._PACK_STR,
323 six.binary_type(binrouter))
324 router = addrconv.ipv4.bin_to_text(router)
325 routers.append(router)
326 buf = buf[cls._PACK_LEN:]
332 def serialize_tail(self):
333 mask = addrconv.ipv4.text_to_bin(self.mask)
334 routers = [addrconv.ipv4.text_to_bin(router)
335 for router in self.routers]
337 struct.pack("!" + "4s" * (1 + len(routers)), mask, *routers))
340 @LSA.register_type(OSPF_SUMMARY_LSA)
341 class SummaryLSA(LSA):
343 _PACK_LEN = struct.calcsize(_PACK_STR)
345 def __init__(self, ls_age=0, options=0, type_=OSPF_SUMMARY_LSA,
346 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
347 checksum=None, length=None, mask='0.0.0.0', tos=0, metric=0):
351 super(SummaryLSA, self).__init__(ls_age, options, type_, id_,
352 adv_router, ls_seqnum, checksum,
356 def parser(cls, buf):
357 if len(buf) < cls._PACK_LEN:
358 raise stream_parser.StreamParser.TooSmallException(
359 '%d < %d' % (len(buf), cls._PACK_LEN))
360 buf = buf[:cls._PACK_LEN]
361 (mask, tos, metric) = struct.unpack_from(
362 cls._PACK_STR, six.binary_type(buf))
363 mask = addrconv.ipv4.bin_to_text(mask)
364 metric = type_desc.Int3.to_user(metric)
371 def serialize_tail(self):
372 mask = addrconv.ipv4.text_to_bin(self.mask)
373 metric = type_desc.Int3.from_user(self.metric)
374 return bytearray(struct.pack(self._PACK_STR, mask, self.tos, metric))
377 @LSA.register_type(OSPF_ASBR_SUMMARY_LSA)
378 class ASBRSummaryLSA(LSA):
382 @LSA.register_type(OSPF_AS_EXTERNAL_LSA)
383 class ASExternalLSA(LSA):
384 class ExternalNetwork(StringifyMixin):
385 _PACK_STR = '!4sB3s4sI'
386 _PACK_LEN = struct.calcsize(_PACK_STR)
388 def __init__(self, mask='0.0.0.0', flags=0, metric=0,
389 fwd_addr='0.0.0.0', tag=0):
393 self.fwd_addr = fwd_addr
397 def parser(cls, buf):
398 if len(buf) < cls._PACK_LEN:
399 raise stream_parser.StreamParser.TooSmallException(
400 '%d < %d' % (len(buf), cls._PACK_LEN))
401 ext_nw = buf[:cls._PACK_LEN]
402 rest = buf[cls._PACK_LEN:]
403 (mask, flags, metric, fwd_addr,
404 tag) = struct.unpack_from(cls._PACK_STR, six.binary_type(ext_nw))
405 mask = addrconv.ipv4.bin_to_text(mask)
406 metric = type_desc.Int3.to_user(metric)
407 fwd_addr = addrconv.ipv4.bin_to_text(fwd_addr)
408 return cls(mask, flags, metric, fwd_addr, tag), rest
411 mask = addrconv.ipv4.text_to_bin(self.mask)
412 metric = type_desc.Int3.from_user(self.metric)
413 fwd_addr = addrconv.ipv4.text_to_bin(self.fwd_addr)
415 struct.pack(self._PACK_STR, mask, self.flags, metric,
418 def __init__(self, ls_age=0, options=0, type_=OSPF_AS_EXTERNAL_LSA,
419 id_='0.0.0.0', adv_router='0.0.0.0', ls_seqnum=0,
420 checksum=None, length=None, extnws=None):
421 extnws = extnws if extnws else []
423 super(ASExternalLSA, self).__init__(ls_age, options, type_, id_,
424 adv_router, ls_seqnum, checksum,
428 def parser(cls, buf):
431 extnw, buf = cls.ExternalNetwork.parser(buf)
437 def serialize_tail(self):
438 return reduce(lambda a, b: a + b,
439 (extnw.serialize() for extnw in self.extnws))
442 @LSA.register_type(OSPF_AS_NSSA_LSA)
443 class NSSAExternalLSA(LSA):
447 class ExtendedPrefixTLV(StringifyMixin, type_desc.TypeDisp):
451 @ExtendedPrefixTLV.register_type(OSPF_EXTENDED_PREFIX_TLV)
452 class ExtendedPrefixTLV(ExtendedPrefixTLV):
453 _VALUE_PACK_STR = '!HHBBBB4s'
454 _VALUE_PACK_LEN = struct.calcsize(_VALUE_PACK_STR)
455 _VALUE_FIELDS = ['route_type', 'prefix_length', 'address_family', '_pad'
458 def __init__(self, type_=OSPF_EXTENDED_PREFIX_TLV, length=0, route_type=0,
459 address_family=0, prefix='0.0.0.0/0'):
462 self.route_type = route_type
463 self.address_family = address_family
467 def parser(cls, buf):
468 rest = buf[cls._VALUE_PACK_LEN:]
469 buf = buf[:cls._VALUE_PACK_LEN]
470 (type_, length, route_type, prefix_length, address_family, _pad,
471 prefix) = struct.unpack_from(cls._VALUE_PACK_STR, buf)
473 prefix = addrconv.ipv4.bin_to_text(prefix)
474 prefix = "%s/%d" % (prefix, prefix_length)
475 return cls(type_, length, route_type, address_family, prefix), rest
478 prefix, prefix_length = self.prefix.split('/')
479 prefix = addrconv.ipv4.text_to_bin(prefix)
480 prefix_length = int(prefix_length)
481 return struct.pack(self._VALUE_PACK_STR, OSPF_EXTENDED_PREFIX_TLV,
482 self._VALUE_PACK_LEN - 4, self.route_type,
483 prefix_length, self.address_family, 0, prefix)
486 @ExtendedPrefixTLV.register_type(OSPF_EXTENDED_PREFIX_SID_SUBTLV)
487 class PrefixSIDSubTLV(ExtendedPrefixTLV):
488 _VALUE_PACK_STR = '!HHBBBBHHI'
489 _VALUE_PACK_LEN = struct.calcsize(_VALUE_PACK_STR)
490 _VALUE_FIELDS = ['flags', 'mt_id', 'algorithm', '_pad', 'range_size',
493 def __init__(self, type_=OSPF_EXTENDED_PREFIX_SID_SUBTLV, length=0,
494 flags=0, mt_id=0, algorithm=0, range_size=0, index=0):
495 super(PrefixSIDSubTLV, self).__init__()
500 self.algorithm = algorithm
501 self.range_size = range_size
505 def parser(cls, buf):
506 rest = buf[cls._VALUE_PACK_LEN:]
507 buf = buf[:cls._VALUE_PACK_LEN]
508 (type_, length, flags, mt_id, algorithm, _pad, range_size, _pad,
509 index) = struct.unpack_from(cls._VALUE_PACK_STR, buf)
511 return cls(type_, length, flags, mt_id, algorithm, range_size,
515 return struct.pack(self._VALUE_PACK_STR,
516 OSPF_EXTENDED_PREFIX_SID_SUBTLV,
517 self._VALUE_PACK_LEN - 4, self.flags, self.mt_id,
518 self.algorithm, 0, self.range_size, 0, self.index)
521 class ExtendedLinkTLV(StringifyMixin, type_desc.TypeDisp):
525 class OpaqueBody(StringifyMixin, type_desc.TypeDisp):
526 def __init__(self, tlvs=None):
527 tlvs = tlvs if tlvs else []
531 return reduce(lambda a, b: a + b,
532 (tlv.serialize() for tlv in self.tlvs))
535 @OpaqueBody.register_type(OSPF_OPAQUE_TYPE_EXTENDED_PREFIX_LSA)
536 class ExtendedPrefixOpaqueBody(OpaqueBody):
538 def parser(cls, buf):
539 buf = six.binary_type(buf)
542 (type_, length) = struct.unpack_from('!HH', buf)
543 if len(buf[struct.calcsize('!HH'):]) < length:
544 raise stream_parser.StreamParser.TooSmallException(
545 '%d < %d' % (len(buf), length))
546 tlvcls = ExtendedPrefixTLV._lookup_type(type_)
548 tlv, buf = tlvcls.parser(buf)
554 @OpaqueBody.register_type(OSPF_OPAQUE_TYPE_EXTENDED_LINK_LSA)
555 class ExtendedLinkOpaqueBody(OpaqueBody):
557 def parser(cls, buf):
558 buf = six.binary_type(buf)
561 (type_, length) = struct.unpack_from('!HH', buf)
562 if len(buf[struct.calcsize('!HH'):]) < length:
563 raise stream_parser.StreamParser.TooSmallException(
564 '%d < %d' % (len(buf), length))
565 tlvcls = ExtendedLinkTLV._lookup_type(type_)
567 tlv, buf = tlvcls.parser(buf)
573 class OpaqueLSA(LSA):
575 def __init__(self, data, *args, **kwargs):
576 super(OpaqueLSA, self).__init__(*args, **kwargs)
580 def parser(cls, buf, opaque_type=OSPF_OPAQUE_TYPE_UNKNOWN):
581 opaquecls = OpaqueBody._lookup_type(opaque_type)
583 data = opaquecls.parser(buf)
586 return {'data': data}
588 def serialize_tail(self):
589 if isinstance(self.data, OpaqueBody):
590 return self.data.serialize()
595 @LSA.register_type(OSPF_OPAQUE_LINK_LSA)
596 class LocalOpaqueLSA(OpaqueLSA):
597 def __init__(self, ls_age=0, options=0, type_=OSPF_OPAQUE_LINK_LSA,
598 adv_router='0.0.0.0', ls_seqnum=0, checksum=0, length=0,
599 opaque_type=OSPF_OPAQUE_TYPE_UNKNOWN, opaque_id=0, data=None):
601 super(LocalOpaqueLSA, self).__init__(ls_age, options, type_, 0,
602 adv_router, ls_seqnum, checksum,
603 length, opaque_type, opaque_id)
606 @LSA.register_type(OSPF_OPAQUE_AREA_LSA)
607 class AreaOpaqueLSA(OpaqueLSA):
608 def __init__(self, ls_age=0, options=0, type_=OSPF_OPAQUE_AREA_LSA,
609 adv_router='0.0.0.0', ls_seqnum=0, checksum=0, length=0,
610 opaque_type=OSPF_OPAQUE_TYPE_UNKNOWN, opaque_id=0, data=None):
612 super(AreaOpaqueLSA, self).__init__(ls_age, options, type_, 0,
613 adv_router, ls_seqnum, checksum,
614 length, opaque_type, opaque_id)
617 @LSA.register_type(OSPF_OPAQUE_AS_LSA)
618 class ASOpaqueLSA(OpaqueLSA):
619 def __init__(self, ls_age=0, options=0, type_=OSPF_OPAQUE_AS_LSA,
620 adv_router='0.0.0.0', ls_seqnum=0, checksum=0, length=0,
621 opaque_type=OSPF_OPAQUE_TYPE_UNKNOWN, opaque_id=0, data=None):
623 super(ASOpaqueLSA, self).__init__(ls_age, options, type_, 0,
624 adv_router, ls_seqnum, checksum,
625 length, opaque_type, opaque_id)
628 class OSPFMessage(packet_base.PacketBase, type_desc.TypeDisp):
629 """Base class for OSPF version 2 messages.
632 _HDR_PACK_STR = '!BBH4s4sHHQ'
633 _HDR_LEN = struct.calcsize(_HDR_PACK_STR)
635 def __init__(self, type_, length=None, router_id='0.0.0.0',
636 area_id='0.0.0.0', au_type=1, authentication=0, checksum=None,
638 super(OSPFMessage, self).__init__()
639 self.version = version
642 self.router_id = router_id
643 self.area_id = area_id
644 self.checksum = checksum
645 self.au_type = au_type
646 self.authentication = authentication
649 def _parser(cls, buf):
650 if len(buf) < cls._HDR_LEN:
651 raise stream_parser.StreamParser.TooSmallException(
652 '%d < %d' % (len(buf), cls._HDR_LEN))
653 (version, type_, length, router_id, area_id, checksum, au_type,
654 authentication) = struct.unpack_from(cls._HDR_PACK_STR,
655 six.binary_type(buf))
657 # Exclude checksum and authentication field for checksum validation.
658 if packet_utils.checksum(buf[:12] + buf[14:16] + buf[cls._HDR_LEN:]) \
660 raise InvalidChecksum
662 if len(buf) < length:
663 raise stream_parser.StreamParser.TooSmallException(
664 '%d < %d' % (len(buf), length))
666 router_id = addrconv.ipv4.bin_to_text(router_id)
667 area_id = addrconv.ipv4.bin_to_text(area_id)
668 binmsg = buf[cls._HDR_LEN:length]
670 subcls = cls._lookup_type(type_)
671 kwargs = subcls.parser(binmsg)
672 return subcls(length, router_id, area_id, au_type, int(authentication),
673 checksum, version, **kwargs), None, rest
676 def parser(cls, buf):
678 return cls._parser(buf)
680 return None, None, buf
682 def serialize(self, payload=None, prev=None):
683 tail = self.serialize_tail()
684 self.length = self._HDR_LEN + len(tail)
686 struct.pack(self._HDR_PACK_STR, self.version,
687 self.type_, self.length,
688 addrconv.ipv4.text_to_bin(self.router_id),
689 addrconv.ipv4.text_to_bin(self.area_id), 0,
690 self.au_type, self.authentication))
692 csum = packet_utils.checksum(buf[:12] + buf[14:16] +
695 struct.pack_into("!H", buf, 12, csum)
703 @OSPFMessage.register_type(OSPF_MSG_HELLO)
704 class OSPFHello(OSPFMessage):
706 _PACK_STR = '!4sHBBI4s4s' # + neighbors
707 _PACK_LEN = struct.calcsize(_PACK_STR)
708 _MIN_LEN = OSPFMessage._HDR_LEN + _PACK_LEN
710 def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
711 au_type=1, authentication=0, checksum=None, version=_VERSION,
712 mask='0.0.0.0', hello_interval=10, options=0, priority=1,
713 dead_interval=40, designated_router='0.0.0.0',
714 backup_router='0.0.0.0', neighbors=None):
715 neighbors = neighbors if neighbors else []
716 super(OSPFHello, self).__init__(OSPF_MSG_HELLO, length, router_id,
717 area_id, au_type, authentication,
720 self.hello_interval = hello_interval
721 self.options = options
722 self.priority = priority
723 self.dead_interval = dead_interval
724 self.designated_router = designated_router
725 self.backup_router = backup_router
726 self.neighbors = neighbors
729 def parser(cls, buf):
730 (mask, hello_interval, options, priority, dead_interval,
731 designated_router, backup_router) = struct.unpack_from(cls._PACK_STR,
732 six.binary_type(buf))
733 mask = addrconv.ipv4.bin_to_text(mask)
734 designated_router = addrconv.ipv4.bin_to_text(designated_router)
735 backup_router = addrconv.ipv4.bin_to_text(backup_router)
737 binneighbors = buf[cls._PACK_LEN:len(buf)]
740 n = addrconv.ipv4.bin_to_text(six.binary_type(n))
741 binneighbors = binneighbors[4:]
745 "hello_interval": hello_interval,
747 "priority": priority,
748 "dead_interval": dead_interval,
749 "designated_router": designated_router,
750 "backup_router": backup_router,
751 "neighbors": neighbors,
754 def serialize_tail(self):
756 struct.pack(self._PACK_STR,
757 addrconv.ipv4.text_to_bin(self.mask),
758 self.hello_interval, self.options, self.priority,
760 addrconv.ipv4.text_to_bin(self.designated_router),
761 addrconv.ipv4.text_to_bin(self.backup_router)))
763 return head + reduce(lambda a, b: a + b,
764 (addrconv.ipv4.text_to_bin(n)
765 for n in self.neighbors))
770 @OSPFMessage.register_type(OSPF_MSG_DB_DESC)
771 class OSPFDBDesc(OSPFMessage):
773 _PACK_STR = '!HBBI' # + LSA_HEADERS
774 _PACK_LEN = struct.calcsize(_PACK_STR)
775 _MIN_LEN = OSPFMessage._HDR_LEN + _PACK_LEN
777 def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
778 au_type=1, authentication=0, checksum=None, version=_VERSION,
779 mtu=1500, options=0, i_flag=0, m_flag=0, ms_flag=0,
780 sequence_number=0, lsa_headers=None):
781 lsa_headers = lsa_headers if lsa_headers else []
782 super(OSPFDBDesc, self).__init__(OSPF_MSG_DB_DESC, length, router_id,
783 area_id, au_type, authentication,
786 self.options = options
789 self.ms_flag = ms_flag
790 self.sequence_number = sequence_number
791 self.lsa_headers = lsa_headers
794 def parser(cls, buf):
795 (mtu, options, flags,
796 sequence_number) = struct.unpack_from(cls._PACK_STR, six.binary_type(buf))
797 i_flag = (flags >> 2) & 0x1
798 m_flag = (flags >> 1) & 0x1
799 ms_flag = flags & 0x1
801 buf = buf[cls._PACK_LEN:]
803 kwargs, buf = LSAHeader.parser(buf)
804 lsahdrs.append(LSAHeader(**kwargs))
811 "sequence_number": sequence_number,
812 "lsa_headers": lsahdrs,
815 def serialize_tail(self):
816 flags = ((self.i_flag & 0x1) << 2) ^ \
817 ((self.m_flag & 0x1) << 1) ^ \
820 struct.pack(self._PACK_STR, self.mtu, self.options, flags,
821 self.sequence_number))
823 return head + reduce(lambda a, b: a + b,
824 (hdr.serialize() for hdr in self.lsa_headers))
829 @OSPFMessage.register_type(OSPF_MSG_LS_REQ)
830 class OSPFLSReq(OSPFMessage):
831 _MIN_LEN = OSPFMessage._HDR_LEN
833 class Request(StringifyMixin):
835 _PACK_LEN = struct.calcsize(_PACK_STR)
837 def __init__(self, type_=OSPF_UNKNOWN_LSA, id_='0.0.0.0',
838 adv_router='0.0.0.0'):
841 self.adv_router = adv_router
844 def parser(cls, buf):
845 if len(buf) < cls._PACK_LEN:
846 raise stream_parser.StreamParser.TooSmallException(
847 '%d < %d' % (len(buf), cls._PACK_LEN))
848 link = buf[:cls._PACK_LEN]
849 rest = buf[cls._PACK_LEN:]
850 (type_, id_, adv_router) = struct.unpack_from(cls._PACK_STR,
851 six.binary_type(link))
852 id_ = addrconv.ipv4.bin_to_text(id_)
853 adv_router = addrconv.ipv4.bin_to_text(adv_router)
854 return cls(type_, id_, adv_router), rest
857 id_ = addrconv.ipv4.text_to_bin(self.id)
858 adv_router = addrconv.ipv4.text_to_bin(self.adv_router)
859 return struct.pack(self._PACK_STR, self.type_, id_, adv_router)
861 def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
862 au_type=1, authentication=0, checksum=None, version=_VERSION,
864 lsa_requests = lsa_requests if lsa_requests else []
865 super(OSPFLSReq, self).__init__(OSPF_MSG_LS_REQ, length, router_id,
866 area_id, au_type, authentication,
868 self.lsa_requests = lsa_requests
871 def parser(cls, buf):
874 req, buf = cls.Request.parser(buf)
877 "lsa_requests": reqs,
880 def serialize_tail(self):
881 return reduce(lambda a, b: a + b,
882 (req.serialize() for req in self.lsa_requests))
885 @OSPFMessage.register_type(OSPF_MSG_LS_UPD)
886 class OSPFLSUpd(OSPFMessage):
888 _PACK_LEN = struct.calcsize(_PACK_STR)
889 _MIN_LEN = OSPFMessage._HDR_LEN + _PACK_LEN
891 def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
892 au_type=1, authentication=0, checksum=None, version=_VERSION,
894 lsas = lsas if lsas else []
895 super(OSPFLSUpd, self).__init__(OSPF_MSG_LS_UPD, length, router_id,
896 area_id, au_type, authentication,
901 def parser(cls, buf):
902 binnum = buf[:cls._PACK_LEN]
903 (num,) = struct.unpack_from(cls._PACK_STR, six.binary_type(binnum))
905 buf = buf[cls._PACK_LEN:]
908 lsa, _cls, buf = LSA.parser(buf)
910 assert len(lsas) == num
915 def serialize_tail(self):
916 head = bytearray(struct.pack(self._PACK_STR, len(self.lsas)))
918 return head + reduce(lambda a, b: a + b,
919 (lsa.serialize() for lsa in self.lsas))
924 @OSPFMessage.register_type(OSPF_MSG_LS_ACK)
925 class OSPFLSAck(OSPFMessage):
926 _MIN_LEN = OSPFMessage._HDR_LEN
928 def __init__(self, length=None, router_id='0.0.0.0', area_id='0.0.0.0',
929 au_type=1, authentication=0, checksum=None, version=_VERSION,
931 lsa_headers = lsa_headers if lsa_headers else []
932 super(OSPFLSAck, self).__init__(OSPF_MSG_LS_ACK, length, router_id,
933 area_id, au_type, authentication,
935 self.lsa_headers = lsa_headers
938 def parser(cls, buf):
941 kwargs, buf = LSAHeader.parser(buf)
942 lsahdrs.append(LSAHeader(**kwargs))
944 "lsa_headers": lsahdrs,
947 def serialize_tail(self):
948 return reduce(lambda a, b: a + b,
949 (hdr.serialize() for hdr in self.lsa_headers))