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