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.
- data/bin/ospfv2 +136 -0
- data/lib/ie/au_type.rb +79 -0
- data/lib/ie/external_route.rb +181 -0
- data/lib/ie/id.rb +97 -0
- data/lib/ie/interface_mtu.rb +64 -0
- data/lib/ie/ls_age.rb +89 -0
- data/lib/ie/ls_type.rb +148 -0
- data/lib/ie/metric.rb +63 -0
- data/lib/ie/mt_metric.rb +119 -0
- data/lib/ie/options.rb +356 -0
- data/lib/ie/ospf_version.rb +67 -0
- data/lib/ie/packet_type.rb +65 -0
- data/lib/ie/router_link.rb +167 -0
- data/lib/ie/router_link_factory.rb +53 -0
- data/lib/ie/router_link_type.rb +86 -0
- data/lib/ie/sequence_number.rb +144 -0
- data/lib/ie/tos_metric.rb +102 -0
- data/lib/infra/ospf_common.rb +291 -0
- data/lib/infra/ospf_constants.rb +73 -0
- data/lib/infra/ospf_io.rb +133 -0
- data/lib/infra/ospf_socket.rb +126 -0
- data/lib/infra/parse_options.rb +135 -0
- data/lib/infra/timer.rb +104 -0
- data/lib/infra/to_s.rb +38 -0
- data/lib/ls_db/advertised_routers.rb +78 -0
- data/lib/ls_db/common.rb +31 -0
- data/lib/ls_db/link_state_database.rb +376 -0
- data/lib/ls_db/link_state_database_build.rb +181 -0
- data/lib/ls_db/link_state_database_links.rb +178 -0
- data/lib/ls_db/links.rb +160 -0
- data/lib/lsa/external.rb +347 -0
- data/lib/lsa/lsa.rb +438 -0
- data/lib/lsa/lsa_factory.rb +59 -0
- data/lib/lsa/network.rb +166 -0
- data/lib/lsa/router.rb +336 -0
- data/lib/lsa/summary.rb +393 -0
- data/lib/neighbor/neighbor.rb +298 -0
- data/lib/neighbor/neighbor_event_handler.rb +61 -0
- data/lib/neighbor/recv_database_description.rb +153 -0
- data/lib/neighbor/recv_hello.rb +53 -0
- data/lib/neighbor/recv_ospf_packet.rb +68 -0
- data/lib/neighbor_sm/attempt_state.rb +44 -0
- data/lib/neighbor_sm/down_state.rb +46 -0
- data/lib/neighbor_sm/exchange_state.rb +32 -0
- data/lib/neighbor_sm/exstart_state.rb +69 -0
- data/lib/neighbor_sm/full_state.rb +36 -0
- data/lib/neighbor_sm/init_state.rb +43 -0
- data/lib/neighbor_sm/loading_state.rb +33 -0
- data/lib/neighbor_sm/neighbor_state.rb +87 -0
- data/lib/packet/database_description.rb +300 -0
- data/lib/packet/hello.rb +327 -0
- data/lib/packet/link_state_ack.rb +144 -0
- data/lib/packet/link_state_request.rb +153 -0
- data/lib/packet/link_state_update.rb +189 -0
- data/lib/packet/ospf_packet.rb +306 -0
- 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
|
data/lib/lsa/network.rb
ADDED
@@ -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
|
+
|