ospfv2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+