ospfv2 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/bin/ospfv2 +136 -0
  2. data/lib/ie/au_type.rb +79 -0
  3. data/lib/ie/external_route.rb +181 -0
  4. data/lib/ie/id.rb +97 -0
  5. data/lib/ie/interface_mtu.rb +64 -0
  6. data/lib/ie/ls_age.rb +89 -0
  7. data/lib/ie/ls_type.rb +148 -0
  8. data/lib/ie/metric.rb +63 -0
  9. data/lib/ie/mt_metric.rb +119 -0
  10. data/lib/ie/options.rb +356 -0
  11. data/lib/ie/ospf_version.rb +67 -0
  12. data/lib/ie/packet_type.rb +65 -0
  13. data/lib/ie/router_link.rb +167 -0
  14. data/lib/ie/router_link_factory.rb +53 -0
  15. data/lib/ie/router_link_type.rb +86 -0
  16. data/lib/ie/sequence_number.rb +144 -0
  17. data/lib/ie/tos_metric.rb +102 -0
  18. data/lib/infra/ospf_common.rb +291 -0
  19. data/lib/infra/ospf_constants.rb +73 -0
  20. data/lib/infra/ospf_io.rb +133 -0
  21. data/lib/infra/ospf_socket.rb +126 -0
  22. data/lib/infra/parse_options.rb +135 -0
  23. data/lib/infra/timer.rb +104 -0
  24. data/lib/infra/to_s.rb +38 -0
  25. data/lib/ls_db/advertised_routers.rb +78 -0
  26. data/lib/ls_db/common.rb +31 -0
  27. data/lib/ls_db/link_state_database.rb +376 -0
  28. data/lib/ls_db/link_state_database_build.rb +181 -0
  29. data/lib/ls_db/link_state_database_links.rb +178 -0
  30. data/lib/ls_db/links.rb +160 -0
  31. data/lib/lsa/external.rb +347 -0
  32. data/lib/lsa/lsa.rb +438 -0
  33. data/lib/lsa/lsa_factory.rb +59 -0
  34. data/lib/lsa/network.rb +166 -0
  35. data/lib/lsa/router.rb +336 -0
  36. data/lib/lsa/summary.rb +393 -0
  37. data/lib/neighbor/neighbor.rb +298 -0
  38. data/lib/neighbor/neighbor_event_handler.rb +61 -0
  39. data/lib/neighbor/recv_database_description.rb +153 -0
  40. data/lib/neighbor/recv_hello.rb +53 -0
  41. data/lib/neighbor/recv_ospf_packet.rb +68 -0
  42. data/lib/neighbor_sm/attempt_state.rb +44 -0
  43. data/lib/neighbor_sm/down_state.rb +46 -0
  44. data/lib/neighbor_sm/exchange_state.rb +32 -0
  45. data/lib/neighbor_sm/exstart_state.rb +69 -0
  46. data/lib/neighbor_sm/full_state.rb +36 -0
  47. data/lib/neighbor_sm/init_state.rb +43 -0
  48. data/lib/neighbor_sm/loading_state.rb +33 -0
  49. data/lib/neighbor_sm/neighbor_state.rb +87 -0
  50. data/lib/packet/database_description.rb +300 -0
  51. data/lib/packet/hello.rb +327 -0
  52. data/lib/packet/link_state_ack.rb +144 -0
  53. data/lib/packet/link_state_request.rb +153 -0
  54. data/lib/packet/link_state_update.rb +189 -0
  55. data/lib/packet/ospf_packet.rb +306 -0
  56. metadata +116 -0
data/lib/lsa/lsa.rb ADDED
@@ -0,0 +1,438 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ =begin rdoc
25
+
26
+ A.4.1 The LSA header
27
+
28
+ All LSAs begin with a common 20 byte header. This header contains
29
+ enough information to uniquely identify the LSA (LS type, Link State
30
+ ID, and Advertising Router). Multiple instances of the LSA may
31
+ exist in the routing domain at the same time. It is then necessary
32
+ to determine which instance is more recent. This is accomplished by
33
+ examining the LS age, LS sequence number and LS checksum fields that
34
+ are also contained in the LSA header.
35
+
36
+
37
+ 0 1 2 3
38
+ 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
39
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40
+ | LS age | Options | LS type |
41
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42
+ | Link State ID |
43
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44
+ | Advertising Router |
45
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46
+ | LS sequence number |
47
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48
+ | LS checksum | length |
49
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50
+
51
+
52
+ LS age
53
+ The time in seconds since the LSA was originated.
54
+
55
+ Options
56
+ The optional capabilities supported by the described portion of
57
+ the routing domain. OSPF's optional capabilities are documented
58
+ in Section A.2.
59
+
60
+ LS type
61
+ The type of the LSA. Each LSA type has a separate advertisement
62
+ format. The LSA types defined in this memo are as follows (see
63
+ Section 12.1.3 for further explanation):
64
+
65
+
66
+ LS Type Description
67
+ ___________________________________
68
+ 1 Router-LSAs
69
+ 2 Network-LSAs
70
+ 3 Summary-LSAs (IP network)
71
+ 4 Summary-LSAs (ASBR)
72
+ 5 AS-external-LSAs
73
+
74
+
75
+ Link State ID
76
+ This field identifies the portion of the internet environment
77
+ that is being described by the LSA. The contents of this field
78
+ depend on the LSA's LS type. For example, in network-LSAs the
79
+ Link State ID is set to the IP interface address of the
80
+ network's Designated Router (from which the network's IP address
81
+ can be derived). The Link State ID is further discussed in
82
+ Section 12.1.4.
83
+
84
+ Advertising Router
85
+ The Router ID of the router that originated the LSA. For
86
+ example, in network-LSAs this field is equal to the Router ID of
87
+ the network's Designated Router.
88
+
89
+ LS sequence number
90
+ Detects old or duplicate LSAs. Successive instances of an LSA
91
+ are given successive LS sequence numbers. See Section 12.1.6
92
+ for more details.
93
+
94
+ LS checksum
95
+ The Fletcher checksum of the complete contents of the LSA,
96
+ including the LSA header but excluding the LS age field. See
97
+ Section 12.1.7 for more details.
98
+
99
+ length
100
+ The length in bytes of the LSA. This includes the 20 byte LSA
101
+ header.
102
+
103
+ =end
104
+
105
+ require 'infra/ospf_common'
106
+ require 'infra/ospf_constants'
107
+ require 'ie/id'
108
+ require 'ie/ls_type'
109
+ require 'ie/ls_age'
110
+ require 'ie/sequence_number'
111
+ require 'ie/options'
112
+ require 'ls_db/advertised_routers'
113
+
114
+ require 'infra/to_s'
115
+
116
+ module OSPFv2
117
+
118
+ class Lsa
119
+ include Comparable
120
+
121
+ AdvertisingRouter = Class.new(Id)
122
+ LsId = Class.new(Id)
123
+ LsAge = Class.new(LsAge)
124
+
125
+ class << self
126
+ def new_ntop(arg)
127
+ lsa = new
128
+ if arg.is_a?(String)
129
+ lsa.parse(arg)
130
+ elsif arg.is_a?(self)
131
+ lsa.parse arg.encode
132
+ else
133
+ raise ArgumentError, "Invalid Argument: #{arg.inspect}"
134
+ end
135
+ lsa
136
+ end
137
+ end
138
+
139
+ include OSPFv2::Common
140
+ include OSPFv2::Constant
141
+
142
+ # FIXME: when adding LSA in LSDB should be acked when init, rxmt otherwise ....
143
+ def ack
144
+ @_rxmt_=false
145
+ end
146
+ def retransmit
147
+ @_rxmt_=true
148
+ end
149
+ def is_acked?
150
+ @_rxmt_ == false
151
+ end
152
+ alias :acked? :is_acked?
153
+ alias :ack? :acked?
154
+
155
+ attr_reader :ls_age, :options, :ls_type
156
+ attr_reader :ls_id
157
+ attr_reader :advertising_router
158
+ attr_reader :sequence_number
159
+
160
+ attr_writer_delegate :advertising_router, :ls_id, :ls_age
161
+
162
+ def initialize(arg={})
163
+ arg = arg.dup
164
+ @ls_age = LsAge.new
165
+ @sequence_number = SequenceNumber.new
166
+ @options = Options.new
167
+ @ls_type = LsType.new klass_to_ls_type
168
+ @ls_id = LsId.new
169
+ @advertising_router = AdvertisingRouter.new
170
+ @_length = 0
171
+ @_rxmt_ = false
172
+
173
+ if arg.is_a?(Hash)
174
+ set arg
175
+ elsif arg.is_a?(String)
176
+ parse arg
177
+ elsif arg.is_a?(self.class)
178
+ parse arg.encode
179
+ else
180
+ raise ArgumentError, "Invalid Argument: #{arg.inspect}"
181
+ end
182
+
183
+ end
184
+
185
+ def sequence_number=(seqn)
186
+ @sequence_number = SequenceNumber.new(seqn)
187
+ end
188
+
189
+ def to_s_default
190
+ len = encode.size
191
+ ls_type_to_s = ls_type.to_sym.to_s.chomp('_lsa')
192
+ sprintf("%-4.0d 0x%2.2x %-8s %-15.15s %-15.15s 0x%8.8x 0x%4.4x %-7d",
193
+ ls_age.to_i, options.to_i, ls_type.to_s_short, ls_id.to_ip, advertising_router.to_ip, seqn.to_I,csum_to_i,len)
194
+ end
195
+ alias :to_s_dd :to_s_default
196
+
197
+ def to_s_verbose
198
+ len = encode.size
199
+ s=[]
200
+ s << self.class.to_s.split('::').last + ":"
201
+ s << ls_age.to_s
202
+ s << options.to_s
203
+ s << ls_type.to_s
204
+ s << advertising_router.to_s
205
+ s << ls_id.to_s
206
+ s << "SequenceNumber: " + sequence_number.to_s
207
+ s << "LS checksum: #{format "%4x", csum_to_i}" if @_csum
208
+ s << "length: #{@_size.unpack('n')}" if @_size
209
+ s.join("\n ")
210
+ end
211
+
212
+ alias :to_s_header :to_s
213
+
214
+ def to_s_junos
215
+ len = encode.size
216
+ sprintf("%-7s %-1.1s%-15.15s %-15.15s 0x%8.8x %4.0d 0x%2.2x 0x%4.4x %3d", LsType.to_junos(ls_type.to_i), '', ls_id.to_ip, advertising_router.to_ip, seqn.to_I, ls_age.to_i, options.to_i, csum_to_i, len)
217
+ end
218
+ include OSPFv2::TO_S
219
+ alias :to_s_junos_verbose :to_s_junos
220
+ #
221
+ # def to_s(*args)
222
+ # return to_s_default(*args) unless defined?($style)
223
+ # case $style
224
+ # when :junos ; to_s_junos(*args)
225
+ # when :junos_verbose ; to_s_junos_verbose(*args)
226
+ # else
227
+ # to_s_default(*args)
228
+ # end
229
+ # end
230
+
231
+ def encode_header
232
+ header = []
233
+ header << ls_age.encode
234
+ header << [options.to_i].pack('C')
235
+ header << ls_type.encode
236
+ header << ls_id.encode
237
+ header << advertising_router.encode
238
+ header << sequence_number.encode
239
+ header << [''].pack('a4')
240
+ header.join
241
+ end
242
+ alias :header_encode :encode_header
243
+
244
+ def header_lsa
245
+ self.class.new self
246
+ end
247
+
248
+ def encode(content='')
249
+ lsa = []
250
+ lsa << encode_header
251
+ lsa << content
252
+ lsa = lsa.join
253
+ lsa[18..19]= @_size = [lsa.size].pack('n')
254
+ lsa[16..17]= self.csum = cheksum(lsa[2..-1], 15).pack('CC')
255
+ lsa
256
+ end
257
+
258
+ def encode_request
259
+ req=[]
260
+ req << ls_id.encode
261
+ req << ls_type.encode
262
+ req << @advertising_router.encode
263
+ req.join
264
+ end
265
+
266
+ def parse(s)
267
+ validate_checksum(s)
268
+ ls_age, options, ls_type, ls_id, advr, seqn, csum, length, lsa = s.unpack('nCCNNNnna*')
269
+ @ls_type = LsType.new ls_type
270
+ @options = Options.new options
271
+ @ls_age = LsAge.new ls_age
272
+ @sequence_number = SequenceNumber.new seqn
273
+ @advertising_router = AdvertisingRouter.new advr
274
+ @ls_id = LsId.new ls_id
275
+ lsa
276
+ end
277
+
278
+ def key
279
+ [ls_type.to_i, ls_id.to_i, advertising_router.to_i]
280
+ end
281
+
282
+ # -1 self older than other
283
+ # 0 self equivalent to other
284
+ # +1 self newer than other
285
+ # FIXME: rename to 'newer'
286
+ # TODO: compare advr router id.
287
+ def <=>(other)
288
+ raise RuntimeError unless self.key == other.key
289
+ if self.sequence_number < other.sequence_number
290
+ # puts "*** jme: our lsa older than other: our seq less than other seq ***"
291
+ -1
292
+ elsif self.sequence_number > other.sequence_number
293
+ # puts "*** jme: our lsa newer than other: our seq greater than other seq ***"
294
+ +1
295
+ else
296
+ if self.csum_to_i < other.csum_to_i
297
+ # puts "*** jme: our lsa older than other: our csum less than other csum ***"
298
+ -1
299
+ elsif self.csum_to_i > other.csum_to_i
300
+ # puts "*** jme: our lsa newer than other: our csum greater than other csum ***"
301
+ +1
302
+ else
303
+ if (self.ls_age != other.ls_age and other.ls_age >= MaxAge) or
304
+ ((other.ls_age - self.ls_age) > OSPFv2::MaxAgeDiff)
305
+ # puts "*** jme: our lsa newer than other: age diff < maxage diff: #{(other.ls_age - self.ls_age)} ***"
306
+ +1
307
+ else
308
+ # puts "*** jme: same lsa: age diff < maxage diff: #{(other.ls_age - self.ls_age)} ***"
309
+ 0
310
+ end
311
+ end
312
+ end
313
+ end
314
+
315
+ def refresh(advertised_routers, refresh_time, seqn=nil)
316
+ return unless advertised_routers.has?(advertising_router)
317
+ return unless refresh?(refresh_time)
318
+ @sequence_number = SequenceNumber.new(seqn) if seqn
319
+ @sequence_number + 1
320
+ @ls_age = LsAge.new
321
+ retransmit
322
+ self
323
+ end
324
+
325
+ def force_refresh(seqn)
326
+ @sequence_number = SequenceNumber.new(seqn) if seqn
327
+ @sequence_number + 1
328
+ @ls_age = LsAge.new
329
+ retransmit
330
+ self
331
+ end
332
+
333
+ def maxage
334
+ ls_age.maxage and retransmit
335
+ self
336
+ end
337
+
338
+ def maxaged?
339
+ @ls_age.maxaged?
340
+ end
341
+
342
+ def to_hash
343
+ h = super
344
+ h.delete(:time)
345
+ h
346
+ end
347
+
348
+ def method_missing(method, *args, &block)
349
+ puts "Method missing in #{self.class}: method: #{method}"
350
+
351
+ if method == :to_s_junos
352
+ :to_s_default
353
+ else
354
+ super
355
+ end
356
+ end
357
+
358
+ protected
359
+
360
+ def csum_to_i
361
+ @_csum.unpack('n')[0]
362
+ rescue Exception => e
363
+ encode
364
+ retry
365
+ end
366
+
367
+
368
+ private
369
+
370
+ def csum=(value)
371
+ raise if value.is_a?(Fixnum)
372
+ @_csum=value
373
+ end
374
+
375
+ def refresh?(refresh_time)
376
+ ls_age.to_i > refresh_time
377
+ end
378
+
379
+ def seqn
380
+ @sequence_number
381
+ end
382
+
383
+ def validate_checksum(s)
384
+ if ! cheksum(s[2..-1], 0) == [0,0]
385
+ puts "*** checksum error ? #{cheksum(s[2..-1], 0)}"
386
+ end
387
+ end
388
+
389
+ def klass_to_ls_type
390
+ case self.class.to_s
391
+ when /Router/ ; 1
392
+ when /Network/ ; 2
393
+ when /Summary/ ; 3
394
+ else
395
+ 1
396
+ end
397
+ end
398
+
399
+ MODX=4102
400
+
401
+ def cheksum(mess, k=0)
402
+ len = mess.size
403
+
404
+ if (k>0)
405
+ mess[k-1] = [0].pack('C')
406
+ mess[k] = [0].pack('C')
407
+ end
408
+
409
+ c0,c1,n=0,0,0
410
+
411
+ s = mess.dup
412
+ while s.size>0 and n <= 4102 # MODX
413
+ n +=1
414
+ c0 += s.slice!(0,1).unpack('C')[0]
415
+ c1 +=c0
416
+ end
417
+
418
+ c0 = c0%255
419
+ c1 = c1%255
420
+
421
+ ip = (c1 <<8) + c0
422
+
423
+ if k>0
424
+ iq = ((len-k)*c0 - c1)%255 ; iq += 255 if (iq <= 0)
425
+ ir = (510 - c0 - iq) ; ir += -255 if (ir>255)
426
+ return [iq,ir]
427
+ else
428
+ [c0,c1]
429
+ end
430
+
431
+ end
432
+
433
+ end
434
+
435
+ end
436
+
437
+ load "../../../test/ospfv2/lsa/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
438
+
@@ -0,0 +1,59 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+ require 'lsa/lsa'
24
+ require 'lsa/router'
25
+ require 'lsa/network'
26
+ require 'lsa/summary'
27
+ require 'lsa/external'
28
+
29
+ module OSPFv2
30
+ class Lsa
31
+ class << self
32
+ def factory(arg)
33
+ if arg.is_a?(String)
34
+ return unless (arg.size>=20)
35
+ case arg[3]
36
+ when 1 ; OSPFv2::Router.new_ntop(arg)
37
+ when 2 ; OSPFv2::Network.new_ntop(arg)
38
+ when 3 ; OSPFv2::Summary.new_ntop(arg)
39
+ when 4 ; OSPFv2::AsbrSummary.new_ntop(arg)
40
+ when 5 ; OSPFv2::AsExternal.new_ntop(arg)
41
+ when 7 ; OSPFv2::AsExternal7.new_ntop(arg)
42
+ end
43
+ elsif arg.is_a?(Hash)
44
+ case arg[:ls_type]
45
+ when :router_lsa ; OSPFv2::Router.new_hash(arg)
46
+ when :network_lsa ; OSPFv2::Network.new_hash(arg)
47
+ when :summary_lsa ; OSPFv2::Summary.new_hash(arg)
48
+ when :asbr_summary_lsa ; OSPFv2::AsbrSummary.new_hash(arg)
49
+ when :as_external_lsa ; OSPFv2::AsExternal.new_hash(arg)
50
+ when :as_external7_lsa ; OSPFv2::AsExternal7.new_hash(arg)
51
+ end
52
+ elsif arg.is_a?(Lsa)
53
+ factory(arg.encode)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ end
@@ -0,0 +1,166 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ =begin rdoc
25
+
26
+
27
+ A.4.3 Network-LSAs
28
+
29
+ Network-LSAs are the Type 2 LSAs. A network-LSA is originated for
30
+ each broadcast and NBMA network in the area which supports two or
31
+ more routers. The network-LSA is originated by the network's
32
+ Designated Router. The LSA describes all routers attached to the
33
+ network, including the Designated Router itself. The LSA's Link
34
+ State ID field lists the IP interface address of the Designated
35
+ Router.
36
+
37
+ The distance from the network to all attached routers is zero. This
38
+ is why metric fields need not be specified in the network-LSA. For
39
+ details concerning the construction of network-LSAs, see Section
40
+ 12.4.2.
41
+
42
+
43
+ 0 1 2 3
44
+ 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
45
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46
+ | LS age | Options | 2 |
47
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48
+ | Link State ID |
49
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50
+ | Advertising Router |
51
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52
+ | LS sequence number |
53
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54
+ | LS checksum | length |
55
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56
+ | Network Mask |
57
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58
+ | Attached Router |
59
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60
+ | ... |
61
+
62
+
63
+
64
+ Network Mask
65
+ The IP address mask for the network. For example, a class A
66
+ network would have the mask 0xff000000.
67
+
68
+
69
+ Attached Router
70
+ The Router IDs of each of the routers attached to the network.
71
+ Actually, only those routers that are fully adjacent to the
72
+ Designated Router are listed. The Designated Router includes
73
+ itself in this list. The number of routers included can be
74
+ deduced from the LSA header's length field.
75
+
76
+
77
+ =end
78
+
79
+ require 'ie/id'
80
+ require 'lsa/lsa'
81
+ module OSPFv2
82
+
83
+ NetworkMask = Class.new(Id)
84
+ AttachRouter = Class.new(Id)
85
+
86
+ class Network < Lsa
87
+
88
+ attr_reader :network_mask, :attached_routers
89
+
90
+ def initialize(arg={})
91
+ @network_mask, @attached_routers = nil, []
92
+ super
93
+ end
94
+
95
+ def encode
96
+ lsa=[]
97
+ @network_mask ||= NetworkMask.new
98
+ @attached_routers ||=[]
99
+ lsa << network_mask.encode
100
+ lsa << attached_routers.collect { |x| x.encode }
101
+ super lsa.join
102
+ end
103
+
104
+ def attached_routers=(val)
105
+ [val].flatten.each { |x| self << x }
106
+ end
107
+
108
+ def <<(neighbor)
109
+ @attached_routers ||=[]
110
+ @attached_routers << AttachRouter.new(neighbor)
111
+ end
112
+
113
+ def parse(s)
114
+ network_mask, attached_routers = super(s).unpack('Na*')
115
+ @network_mask = NetworkMask.new network_mask
116
+ while attached_routers.size>0
117
+ self << attached_routers.slice!(0,4).unpack('N')[0]
118
+ end
119
+ end
120
+
121
+ # Network:
122
+ # LsAge: 34
123
+ # Options: 0x22 [DC,E]
124
+ # LsType: network_lsa
125
+ # AdvertisingRouter: 192.168.1.200
126
+ # LsId: 192.168.1.200
127
+ # SequenceNumber: 0x80000001
128
+ # LS checksum: 2dc
129
+ # length: 32
130
+ # NetworkMask: 255.255.255.0
131
+ # AttachRouter: 192.168.1.200
132
+ # AttachRouter: 193.0.0.0
133
+ def to_s_default(*args)
134
+ super +
135
+ ['', network_mask, *attached_routers].join("\n ")
136
+ end
137
+
138
+ # Network *192.168.1.200 192.168.1.200 0x80000001 98 0x22 0x2dc 32
139
+ # mask 255.255.255.0
140
+ # attached router 192.168.1.200
141
+ # attached router 193.0.0.0
142
+ #
143
+ def to_s_junos
144
+ super
145
+ end
146
+
147
+ def to_s_junos_verbose
148
+ mask = "mask #{network_mask.to_ip}"
149
+ attrs = attached_routers.collect { |ar| "attached router #{ar.to_ip}"}
150
+ super +
151
+ ['', mask, *attrs].join("\n ")
152
+ end
153
+
154
+ end
155
+
156
+ class Network
157
+ def self.new_hash(h)
158
+ r = new(h)
159
+ r
160
+ end
161
+ end
162
+
163
+ end
164
+
165
+ load "../../../test/ospfv2/lsa/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
166
+