ospfv2 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/ospfv2 +3 -6
- data/changelog.txt +8 -0
- data/lib/ie/au_type.rb +1 -1
- data/lib/ie/external_route.rb +6 -3
- data/lib/ie/interface_mtu.rb +0 -1
- data/lib/ie/ls_age.rb +2 -16
- data/lib/ie/ls_type.rb +106 -73
- data/lib/ie/metric.rb +13 -0
- data/lib/ie/options.rb +42 -21
- data/lib/ie/ospf_version.rb +0 -8
- data/lib/ie/router_link.rb +7 -28
- data/lib/ie/sequence_number.rb +6 -1
- data/lib/infra/ospf_common.rb +2 -13
- data/lib/infra/ospf_constants.rb +8 -8
- data/lib/infra/ospf_io.rb +1 -1
- data/lib/infra/ospf_socket.rb +12 -20
- data/lib/infra/parse_options.rb +3 -3
- data/lib/infra/timer.rb +2 -1
- data/lib/ls_db/advertised_routers.rb +30 -28
- data/lib/ls_db/link_state_database.rb +8 -50
- data/lib/ls_db/link_state_database_build.rb +5 -5
- data/lib/ls_db/links.rb +1 -4
- data/lib/lsa/external.rb +13 -11
- data/lib/lsa/lsa.rb +81 -43
- data/lib/lsa/lsa_base.rb +430 -0
- data/lib/lsa/lsa_factory.rb +5 -1
- data/lib/lsa/network.rb +7 -2
- data/lib/lsa/opaque.rb +143 -0
- data/lib/lsa/router.rb +17 -25
- data/lib/lsa/summary.rb +17 -171
- data/lib/lsa/tlv/tlv.rb +0 -0
- data/lib/neighbor/neighbor.rb +24 -9
- data/lib/neighbor/recv_hello.rb +0 -5
- data/lib/neighbor/recv_ospf_packet.rb +1 -2
- data/lib/neighbor_sm/exstart_state.rb +9 -12
- data/lib/neighbor_sm/init_state.rb +5 -7
- data/lib/packet/database_description.rb +7 -7
- data/lib/packet/hello.rb +94 -12
- data/lib/packet/link_state_ack.rb +2 -2
- data/lib/packet/link_state_update.rb +1 -1
- data/lib/packet/ospf_packet.rb +4 -5
- metadata +16 -8
@@ -52,14 +52,14 @@ module OSPFv2::LSDB
|
|
52
52
|
raise ArgumentError, "missing prefix" unless prefix
|
53
53
|
raise ArgumentError, "missing neighbor router id" unless neighbor_id
|
54
54
|
|
55
|
-
_, addr, plen, network, netmask = IPAddr.
|
55
|
+
_, addr, plen, network, netmask = IPAddr.to_arr(prefix)
|
56
56
|
|
57
57
|
# if not set assume router id is the interface address given to us in :prefix
|
58
58
|
router_id ||= addr
|
59
59
|
|
60
60
|
|
61
61
|
# router_id to list of advertised routers
|
62
|
-
advertised_routers
|
62
|
+
advertised_routers << router_id
|
63
63
|
|
64
64
|
rlsa = find_router_lsa router_id
|
65
65
|
|
@@ -72,7 +72,7 @@ module OSPFv2::LSDB
|
|
72
72
|
:ls_type=>:router_lsa,
|
73
73
|
:options=> 0x22
|
74
74
|
|
75
|
-
advertised_routers
|
75
|
+
advertised_routers << router_id
|
76
76
|
|
77
77
|
# add to lsdb
|
78
78
|
self << rlsa
|
@@ -97,7 +97,7 @@ module OSPFv2::LSDB
|
|
97
97
|
|
98
98
|
def remove_adjacency(rid, neighbor_id, prefix)
|
99
99
|
if (rlsa = lookup(:router_lsa, rid))
|
100
|
-
addr, source_address, plen, network, netmask = IPAddr.
|
100
|
+
addr, source_address, plen, network, netmask = IPAddr.to_arr(prefix)
|
101
101
|
rlsa.delete(:point_to_point,id2ip(neighbor_id))
|
102
102
|
rlsa.delete(3,network)
|
103
103
|
end
|
@@ -139,7 +139,7 @@ module OSPFv2::LSDB
|
|
139
139
|
:ls_type=>:router_lsa,
|
140
140
|
:options=> 0x22
|
141
141
|
|
142
|
-
advertised_routers
|
142
|
+
advertised_routers << router_id
|
143
143
|
|
144
144
|
# add to lsdb
|
145
145
|
self << rlsa
|
data/lib/ls_db/links.rb
CHANGED
@@ -140,15 +140,12 @@ module OSPFv2::LSDB
|
|
140
140
|
if name.to_s =~ /^(local|remote)_address/
|
141
141
|
(__send__ "#{$1}_prefix").split('/')[0]
|
142
142
|
else
|
143
|
-
|
144
|
-
raise
|
143
|
+
super
|
145
144
|
end
|
146
145
|
end
|
147
146
|
|
148
|
-
|
149
147
|
private
|
150
148
|
|
151
|
-
|
152
149
|
def _address_(host=1)
|
153
150
|
network + host
|
154
151
|
end
|
data/lib/lsa/external.rb
CHANGED
@@ -155,17 +155,19 @@ module OSPFv2
|
|
155
155
|
|
156
156
|
class External_Base < Lsa
|
157
157
|
|
158
|
-
|
159
|
-
|
160
|
-
|
158
|
+
unless const_defined?(:Netmask)
|
159
|
+
Netmask = Class.new(OSPFv2::Id)
|
160
|
+
ExternalRoute = Class.new(OSPFv2::ExternalRoute)
|
161
|
+
end
|
161
162
|
|
162
163
|
attr_reader :netmask, :external_route, :mt_metrics
|
163
164
|
attr_writer_delegate :netmask, :external_route
|
164
165
|
|
165
|
-
def initialize(arg={})
|
166
|
+
def initialize(ls_type, arg={})
|
166
167
|
@netmask, @external_route = nil
|
167
168
|
@mt_metrics=[]
|
168
|
-
|
169
|
+
@ls_type = LsType.new(ls_type)
|
170
|
+
super arg
|
169
171
|
end
|
170
172
|
|
171
173
|
def encode
|
@@ -277,7 +279,9 @@ module OSPFv2
|
|
277
279
|
|
278
280
|
class AsExternal < External_Base
|
279
281
|
|
280
|
-
|
282
|
+
unless const_defined?(:ExternalRoute)
|
283
|
+
ExternalRoute = Class.new(OSPFv2::ExternalRoute)
|
284
|
+
end
|
281
285
|
|
282
286
|
class << self
|
283
287
|
def count
|
@@ -308,11 +312,9 @@ module OSPFv2
|
|
308
312
|
end
|
309
313
|
|
310
314
|
def initialize(arg={})
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
super
|
315
|
-
end
|
315
|
+
arg = fix_hash(arg) if arg.is_a?(Hash)
|
316
|
+
super 5, arg
|
317
|
+
end
|
316
318
|
|
317
319
|
private
|
318
320
|
|
data/lib/lsa/lsa.rb
CHANGED
@@ -49,6 +49,28 @@ are also contained in the LSA header.
|
|
49
49
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
50
50
|
|
51
51
|
|
52
|
+
0 1 2 3
|
53
|
+
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
|
54
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
55
|
+
| LS age | Options | 9, 10, or 11 |
|
56
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
57
|
+
| Opaque Type | Opaque ID |
|
58
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
59
|
+
| Advertising Router |
|
60
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
61
|
+
| LS Sequence Number |
|
62
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
63
|
+
| LS checksum | Length |
|
64
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
65
|
+
| |
|
66
|
+
+ +
|
67
|
+
| Opaque Information |
|
68
|
+
+ +
|
69
|
+
| ... |
|
70
|
+
#
|
71
|
+
|
72
|
+
|
73
|
+
|
52
74
|
LS age
|
53
75
|
The time in seconds since the LSA was originated.
|
54
76
|
|
@@ -118,9 +140,12 @@ module OSPFv2
|
|
118
140
|
class Lsa
|
119
141
|
include Comparable
|
120
142
|
|
121
|
-
|
122
|
-
|
123
|
-
|
143
|
+
unless const_defined?(:AdvertisingRouter)
|
144
|
+
AdvertisingRouter = Class.new(Id)
|
145
|
+
LsId = Class.new(Id)
|
146
|
+
LsAge = Class.new(LsAge)
|
147
|
+
MODX=4102
|
148
|
+
end
|
124
149
|
|
125
150
|
class << self
|
126
151
|
def new_ntop(arg)
|
@@ -152,7 +177,7 @@ module OSPFv2
|
|
152
177
|
alias :acked? :is_acked?
|
153
178
|
alias :ack? :acked?
|
154
179
|
|
155
|
-
attr_reader :ls_age, :options
|
180
|
+
attr_reader :ls_age, :options
|
156
181
|
attr_reader :ls_id
|
157
182
|
attr_reader :advertising_router
|
158
183
|
attr_reader :sequence_number
|
@@ -164,12 +189,16 @@ module OSPFv2
|
|
164
189
|
@ls_age = LsAge.new
|
165
190
|
@sequence_number = SequenceNumber.new
|
166
191
|
@options = Options.new
|
167
|
-
@ls_type = LsType.new klass_to_ls_type
|
168
192
|
@ls_id = LsId.new
|
169
193
|
@advertising_router = AdvertisingRouter.new
|
170
194
|
@_length = 0
|
171
195
|
@_rxmt_ = false
|
172
196
|
|
197
|
+
# unless @ls_type
|
198
|
+
# # raise if caller[-2].grep(/test\/unit/).empty?
|
199
|
+
# @ls_type = LsType.new(1)
|
200
|
+
# end
|
201
|
+
|
173
202
|
if arg.is_a?(Hash)
|
174
203
|
set arg
|
175
204
|
elsif arg.is_a?(String)
|
@@ -182,15 +211,21 @@ module OSPFv2
|
|
182
211
|
|
183
212
|
end
|
184
213
|
|
214
|
+
def ls_type
|
215
|
+
@ls_type ||= LsType.new(1)
|
216
|
+
end
|
217
|
+
|
185
218
|
def sequence_number=(seqn)
|
186
219
|
@sequence_number = SequenceNumber.new(seqn)
|
187
220
|
end
|
188
221
|
|
189
222
|
def to_s_default
|
190
223
|
len = encode.size
|
191
|
-
|
192
|
-
|
193
|
-
|
224
|
+
if is_opaque?
|
225
|
+
else
|
226
|
+
sprintf("%-4.0d 0x%2.2x %-8s %-15.15s %-15.15s 0x%8.8x 0x%4.4x %-7d",
|
227
|
+
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)
|
228
|
+
end
|
194
229
|
end
|
195
230
|
alias :to_s_dd :to_s_default
|
196
231
|
|
@@ -202,7 +237,11 @@ module OSPFv2
|
|
202
237
|
s << options.to_s
|
203
238
|
s << ls_type.to_s
|
204
239
|
s << advertising_router.to_s
|
205
|
-
|
240
|
+
if is_opaque?
|
241
|
+
# s << ls_id.to_s
|
242
|
+
else
|
243
|
+
s << ls_id.to_s
|
244
|
+
end
|
206
245
|
s << "SequenceNumber: " + sequence_number.to_s
|
207
246
|
s << "LS checksum: #{format "%4x", csum_to_i}" if @_csum
|
208
247
|
s << "length: #{@_size.unpack('n')}" if @_size
|
@@ -213,31 +252,39 @@ module OSPFv2
|
|
213
252
|
|
214
253
|
def to_s_junos
|
215
254
|
len = encode.size
|
216
|
-
|
255
|
+
if is_opaque?
|
256
|
+
else
|
257
|
+
sprintf("%-7s %-1.1s%-15.15s %-15.15s 0x%8.8x %4.0d 0x%2.2x 0x%4.4x %3d", ls_type.to_junos, '', ls_id.to_ip, advertising_router.to_ip, seqn.to_I, ls_age.to_i, options.to_i, csum_to_i, len)
|
258
|
+
end
|
217
259
|
end
|
218
260
|
include OSPFv2::TO_S
|
219
261
|
alias :to_s_junos_verbose :to_s_junos
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
# when :junos_verbose ; to_s_junos_verbose(*args)
|
226
|
-
# else
|
227
|
-
# to_s_default(*args)
|
228
|
-
# end
|
229
|
-
# end
|
230
|
-
|
262
|
+
|
263
|
+
def is_opaque?
|
264
|
+
ls_type.is_opaque?
|
265
|
+
end
|
266
|
+
|
231
267
|
def encode_header
|
232
268
|
header = []
|
233
269
|
header << ls_age.encode
|
234
270
|
header << [options.to_i].pack('C')
|
235
271
|
header << ls_type.encode
|
236
|
-
|
272
|
+
if is_opaque?
|
273
|
+
header << [(@opaque_type << 24) + @opaque_id].pack('N')
|
274
|
+
else
|
275
|
+
header << ls_id.encode
|
276
|
+
end
|
237
277
|
header << advertising_router.encode
|
238
278
|
header << sequence_number.encode
|
239
279
|
header << [''].pack('a4')
|
240
280
|
header.join
|
281
|
+
rescue => e
|
282
|
+
p ls_age
|
283
|
+
p ls_type
|
284
|
+
p ls_id
|
285
|
+
p advertising_router
|
286
|
+
p sequence_number
|
287
|
+
raise
|
241
288
|
end
|
242
289
|
alias :header_encode :encode_header
|
243
290
|
|
@@ -271,7 +318,12 @@ module OSPFv2
|
|
271
318
|
@ls_age = LsAge.new ls_age
|
272
319
|
@sequence_number = SequenceNumber.new seqn
|
273
320
|
@advertising_router = AdvertisingRouter.new advr
|
274
|
-
|
321
|
+
if is_opaque?
|
322
|
+
@opaque_id = ls_id >> 24
|
323
|
+
@opaque_type = ls_id & 0xffffff
|
324
|
+
else
|
325
|
+
@ls_id = LsId.new ls_id
|
326
|
+
end
|
275
327
|
lsa
|
276
328
|
end
|
277
329
|
|
@@ -282,7 +334,6 @@ module OSPFv2
|
|
282
334
|
# -1 self older than other
|
283
335
|
# 0 self equivalent to other
|
284
336
|
# +1 self newer than other
|
285
|
-
# FIXME: rename to 'newer'
|
286
337
|
# TODO: compare advr router id.
|
287
338
|
def <=>(other)
|
288
339
|
raise RuntimeError unless self.key == other.key
|
@@ -316,7 +367,7 @@ module OSPFv2
|
|
316
367
|
return unless advertised_routers.has?(advertising_router)
|
317
368
|
return unless refresh?(refresh_time)
|
318
369
|
@sequence_number = SequenceNumber.new(seqn) if seqn
|
319
|
-
@sequence_number
|
370
|
+
@sequence_number.incr
|
320
371
|
@ls_age = LsAge.new
|
321
372
|
retransmit
|
322
373
|
self
|
@@ -324,7 +375,7 @@ module OSPFv2
|
|
324
375
|
|
325
376
|
def force_refresh(seqn)
|
326
377
|
@sequence_number = SequenceNumber.new(seqn) if seqn
|
327
|
-
@sequence_number
|
378
|
+
@sequence_number.incr
|
328
379
|
@ls_age = LsAge.new
|
329
380
|
retransmit
|
330
381
|
self
|
@@ -346,8 +397,8 @@ module OSPFv2
|
|
346
397
|
end
|
347
398
|
|
348
399
|
def method_missing(method, *args, &block)
|
349
|
-
puts "
|
350
|
-
|
400
|
+
# puts "&&&&& #{self.class}: method: #{method}"
|
401
|
+
# p caller[0]
|
351
402
|
if method == :to_s_junos
|
352
403
|
:to_s_default
|
353
404
|
else
|
@@ -385,19 +436,7 @@ module OSPFv2
|
|
385
436
|
puts "*** checksum error ? #{cheksum(s[2..-1], 0)}"
|
386
437
|
end
|
387
438
|
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
|
-
|
439
|
+
|
401
440
|
def cheksum(mess, k=0)
|
402
441
|
len = mess.size
|
403
442
|
|
@@ -418,7 +457,7 @@ module OSPFv2
|
|
418
457
|
c0 = c0%255
|
419
458
|
c1 = c1%255
|
420
459
|
|
421
|
-
ip = (c1
|
460
|
+
ip = (c1<<8) + c0
|
422
461
|
|
423
462
|
if k>0
|
424
463
|
iq = ((len-k)*c0 - c1)%255 ; iq += 255 if (iq <= 0)
|
@@ -435,4 +474,3 @@ module OSPFv2
|
|
435
474
|
end
|
436
475
|
|
437
476
|
load "../../../test/ospfv2/lsa/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
438
|
-
|
data/lib/lsa/lsa_base.rb
ADDED
@@ -0,0 +1,430 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
A.4.1 The LSA header
|
5
|
+
|
6
|
+
All LSAs begin with a common 20 byte header. This header contains
|
7
|
+
enough information to uniquely identify the LSA (LS type, Link State
|
8
|
+
ID, and Advertising Router). Multiple instances of the LSA may
|
9
|
+
exist in the routing domain at the same time. It is then necessary
|
10
|
+
to determine which instance is more recent. This is accomplished by
|
11
|
+
examining the LS age, LS sequence number and LS checksum fields that
|
12
|
+
are also contained in the LSA header.
|
13
|
+
|
14
|
+
|
15
|
+
0 1 2 3
|
16
|
+
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
|
17
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
18
|
+
| LS age | Options | LS type |
|
19
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
20
|
+
| Link State ID |
|
21
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
22
|
+
| Advertising Router |
|
23
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
24
|
+
| LS sequence number |
|
25
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
26
|
+
| LS checksum | length |
|
27
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
0 1 2 3
|
32
|
+
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
|
33
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
34
|
+
| LS age | Options | 9, 10, or 11 |
|
35
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
36
|
+
| Opaque Type | Opaque ID |
|
37
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
38
|
+
| Advertising Router |
|
39
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
40
|
+
| LS Sequence Number |
|
41
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
42
|
+
| LS checksum | Length |
|
43
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
44
|
+
| |
|
45
|
+
+ +
|
46
|
+
| Opaque Information |
|
47
|
+
+ +
|
48
|
+
| ... |
|
49
|
+
#
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
LS age
|
54
|
+
The time in seconds since the LSA was originated.
|
55
|
+
|
56
|
+
Options
|
57
|
+
The optional capabilities supported by the described portion of
|
58
|
+
the routing domain. OSPF's optional capabilities are documented
|
59
|
+
in Section A.2.
|
60
|
+
|
61
|
+
LS type
|
62
|
+
The type of the LSA. Each LSA type has a separate advertisement
|
63
|
+
format. The LSA types defined in this memo are as follows (see
|
64
|
+
Section 12.1.3 for further explanation):
|
65
|
+
|
66
|
+
|
67
|
+
LS Type Description
|
68
|
+
___________________________________
|
69
|
+
1 Router-LSAs
|
70
|
+
2 Network-LSAs
|
71
|
+
3 Summary-LSAs (IP network)
|
72
|
+
4 Summary-LSAs (ASBR)
|
73
|
+
5 AS-external-LSAs
|
74
|
+
|
75
|
+
|
76
|
+
Link State ID
|
77
|
+
This field identifies the portion of the internet environment
|
78
|
+
that is being described by the LSA. The contents of this field
|
79
|
+
depend on the LSA's LS type. For example, in network-LSAs the
|
80
|
+
Link State ID is set to the IP interface address of the
|
81
|
+
network's Designated Router (from which the network's IP address
|
82
|
+
can be derived). The Link State ID is further discussed in
|
83
|
+
Section 12.1.4.
|
84
|
+
|
85
|
+
Advertising Router
|
86
|
+
The Router ID of the router that originated the LSA. For
|
87
|
+
example, in network-LSAs this field is equal to the Router ID of
|
88
|
+
the network's Designated Router.
|
89
|
+
|
90
|
+
LS sequence number
|
91
|
+
Detects old or duplicate LSAs. Successive instances of an LSA
|
92
|
+
are given successive LS sequence numbers. See Section 12.1.6
|
93
|
+
for more details.
|
94
|
+
|
95
|
+
LS checksum
|
96
|
+
The Fletcher checksum of the complete contents of the LSA,
|
97
|
+
including the LSA header but excluding the LS age field. See
|
98
|
+
Section 12.1.7 for more details.
|
99
|
+
|
100
|
+
length
|
101
|
+
The length in bytes of the LSA. This includes the 20 byte LSA
|
102
|
+
header.
|
103
|
+
|
104
|
+
=end
|
105
|
+
|
106
|
+
require 'infra/ospf_common'
|
107
|
+
require 'infra/ospf_constants'
|
108
|
+
require 'ie/id'
|
109
|
+
require 'ie/ls_type'
|
110
|
+
require 'ie/ls_age'
|
111
|
+
require 'ie/sequence_number'
|
112
|
+
require 'ie/options'
|
113
|
+
require 'ls_db/advertised_routers'
|
114
|
+
|
115
|
+
require 'infra/to_s'
|
116
|
+
|
117
|
+
module OSPFv2
|
118
|
+
|
119
|
+
class Lsa_Base
|
120
|
+
include Comparable
|
121
|
+
|
122
|
+
AdvertisingRouter = Class.new(Id)
|
123
|
+
LsId = Class.new(Id)
|
124
|
+
LsAge = Class.new(LsAge)
|
125
|
+
|
126
|
+
class << self
|
127
|
+
def new_ntop(arg)
|
128
|
+
lsa = new
|
129
|
+
if arg.is_a?(String)
|
130
|
+
lsa.parse(arg)
|
131
|
+
elsif arg.is_a?(self)
|
132
|
+
lsa.parse arg.encode
|
133
|
+
else
|
134
|
+
raise ArgumentError, "Invalid Argument: #{arg.inspect}"
|
135
|
+
end
|
136
|
+
lsa
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
include OSPFv2::Common
|
141
|
+
include OSPFv2::Constant
|
142
|
+
|
143
|
+
# FIXME: when adding LSA in LSDB should be acked when init, rxmt otherwise ....
|
144
|
+
def ack
|
145
|
+
@_rxmt_=false
|
146
|
+
end
|
147
|
+
def retransmit
|
148
|
+
@_rxmt_=true
|
149
|
+
end
|
150
|
+
def is_acked?
|
151
|
+
@_rxmt_ == false
|
152
|
+
end
|
153
|
+
alias :acked? :is_acked?
|
154
|
+
alias :ack? :acked?
|
155
|
+
|
156
|
+
attr_reader :ls_age, :options, :ls_type
|
157
|
+
attr_reader :ls_id
|
158
|
+
attr_reader :advertising_router
|
159
|
+
attr_reader :sequence_number
|
160
|
+
|
161
|
+
attr_writer_delegate :advertising_router, :ls_id, :ls_age
|
162
|
+
|
163
|
+
def initialize(arg={})
|
164
|
+
arg = arg.dup
|
165
|
+
@ls_age = LsAge.new
|
166
|
+
@sequence_number = SequenceNumber.new
|
167
|
+
@options = Options.new
|
168
|
+
@ls_type = LsType.new klass_to_ls_type
|
169
|
+
@ls_id = LsId.new
|
170
|
+
@advertising_router = AdvertisingRouter.new
|
171
|
+
@_length = 0
|
172
|
+
@_rxmt_ = false
|
173
|
+
|
174
|
+
if arg.is_a?(Hash)
|
175
|
+
set arg
|
176
|
+
elsif arg.is_a?(String)
|
177
|
+
parse arg
|
178
|
+
elsif arg.is_a?(self.class)
|
179
|
+
parse arg.encode
|
180
|
+
else
|
181
|
+
raise ArgumentError, "Invalid Argument: #{arg.inspect}"
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
def sequence_number=(seqn)
|
187
|
+
@sequence_number = SequenceNumber.new(seqn)
|
188
|
+
end
|
189
|
+
|
190
|
+
def to_s_default
|
191
|
+
len = encode.size
|
192
|
+
ls_type_to_s = ls_type.to_sym.to_s.chomp('_lsa')
|
193
|
+
sprintf("%-4.0d 0x%2.2x %-8s %-15.15s %-15.15s 0x%8.8x 0x%4.4x %-7d",
|
194
|
+
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)
|
195
|
+
end
|
196
|
+
alias :to_s_dd :to_s_default
|
197
|
+
|
198
|
+
def to_s_verbose
|
199
|
+
len = encode.size
|
200
|
+
s=[]
|
201
|
+
s << self.class.to_s.split('::').last + ":"
|
202
|
+
s << ls_age.to_s
|
203
|
+
s << options.to_s
|
204
|
+
s << ls_type.to_s
|
205
|
+
s << advertising_router.to_s
|
206
|
+
s << ls_id.to_s
|
207
|
+
s << "SequenceNumber: " + sequence_number.to_s
|
208
|
+
s << "LS checksum: #{format "%4x", csum_to_i}" if @_csum
|
209
|
+
s << "length: #{@_size.unpack('n')}" if @_size
|
210
|
+
s.join("\n ")
|
211
|
+
end
|
212
|
+
|
213
|
+
alias :to_s_header :to_s
|
214
|
+
|
215
|
+
def to_s_junos
|
216
|
+
len = encode.size
|
217
|
+
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)
|
218
|
+
end
|
219
|
+
include OSPFv2::TO_S
|
220
|
+
alias :to_s_junos_verbose :to_s_junos
|
221
|
+
|
222
|
+
def encode_header
|
223
|
+
header = []
|
224
|
+
header << ls_age.encode
|
225
|
+
header << [options.to_i].pack('C')
|
226
|
+
header << ls_type.encode
|
227
|
+
header << ls_id.encode
|
228
|
+
header << advertising_router.encode
|
229
|
+
header << sequence_number.encode
|
230
|
+
header << [''].pack('a4')
|
231
|
+
header.join
|
232
|
+
end
|
233
|
+
alias :header_encode :encode_header
|
234
|
+
|
235
|
+
def header_lsa
|
236
|
+
self.class.new self
|
237
|
+
end
|
238
|
+
|
239
|
+
def encode(content='')
|
240
|
+
lsa = []
|
241
|
+
lsa << encode_header
|
242
|
+
lsa << content
|
243
|
+
lsa = lsa.join
|
244
|
+
lsa[18..19]= @_size = [lsa.size].pack('n')
|
245
|
+
lsa[16..17]= self.csum = cheksum(lsa[2..-1], 15).pack('CC')
|
246
|
+
lsa
|
247
|
+
end
|
248
|
+
|
249
|
+
def encode_request
|
250
|
+
req=[]
|
251
|
+
req << ls_id.encode
|
252
|
+
req << ls_type.encode
|
253
|
+
req << @advertising_router.encode
|
254
|
+
req.join
|
255
|
+
end
|
256
|
+
|
257
|
+
def parse(s)
|
258
|
+
validate_checksum(s)
|
259
|
+
ls_age, options, ls_type, ls_id, advr, seqn, csum, length, lsa = s.unpack('nCCNNNnna*')
|
260
|
+
@ls_type = LsType.new ls_type
|
261
|
+
@options = Options.new options
|
262
|
+
@ls_age = LsAge.new ls_age
|
263
|
+
@sequence_number = SequenceNumber.new seqn
|
264
|
+
@advertising_router = AdvertisingRouter.new advr
|
265
|
+
@ls_id = LsId.new ls_id
|
266
|
+
lsa
|
267
|
+
end
|
268
|
+
|
269
|
+
def key
|
270
|
+
[ls_type.to_i, ls_id.to_i, advertising_router.to_i]
|
271
|
+
end
|
272
|
+
|
273
|
+
# -1 self older than other
|
274
|
+
# 0 self equivalent to other
|
275
|
+
# +1 self newer than other
|
276
|
+
# FIXME: rename to 'newer'
|
277
|
+
# TODO: compare advr router id.
|
278
|
+
def <=>(other)
|
279
|
+
raise RuntimeError unless self.key == other.key
|
280
|
+
if self.sequence_number < other.sequence_number
|
281
|
+
# puts "*** jme: our lsa older than other: our seq less than other seq ***"
|
282
|
+
-1
|
283
|
+
elsif self.sequence_number > other.sequence_number
|
284
|
+
# puts "*** jme: our lsa newer than other: our seq greater than other seq ***"
|
285
|
+
+1
|
286
|
+
else
|
287
|
+
if self.csum_to_i < other.csum_to_i
|
288
|
+
# puts "*** jme: our lsa older than other: our csum less than other csum ***"
|
289
|
+
-1
|
290
|
+
elsif self.csum_to_i > other.csum_to_i
|
291
|
+
# puts "*** jme: our lsa newer than other: our csum greater than other csum ***"
|
292
|
+
+1
|
293
|
+
else
|
294
|
+
if (self.ls_age != other.ls_age and other.ls_age >= MaxAge) or
|
295
|
+
((other.ls_age - self.ls_age) > OSPFv2::MaxAgeDiff)
|
296
|
+
# puts "*** jme: our lsa newer than other: age diff < maxage diff: #{(other.ls_age - self.ls_age)} ***"
|
297
|
+
+1
|
298
|
+
else
|
299
|
+
# puts "*** jme: same lsa: age diff < maxage diff: #{(other.ls_age - self.ls_age)} ***"
|
300
|
+
0
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def refresh(advertised_routers, refresh_time, seqn=nil)
|
307
|
+
return unless advertised_routers.has?(advertising_router)
|
308
|
+
return unless refresh?(refresh_time)
|
309
|
+
@sequence_number = SequenceNumber.new(seqn) if seqn
|
310
|
+
@sequence_number + 1
|
311
|
+
@ls_age = LsAge.new
|
312
|
+
retransmit
|
313
|
+
self
|
314
|
+
end
|
315
|
+
|
316
|
+
def force_refresh(seqn)
|
317
|
+
@sequence_number = SequenceNumber.new(seqn) if seqn
|
318
|
+
@sequence_number + 1
|
319
|
+
@ls_age = LsAge.new
|
320
|
+
retransmit
|
321
|
+
self
|
322
|
+
end
|
323
|
+
|
324
|
+
def maxage
|
325
|
+
ls_age.maxage and retransmit
|
326
|
+
self
|
327
|
+
end
|
328
|
+
|
329
|
+
def maxaged?
|
330
|
+
@ls_age.maxaged?
|
331
|
+
end
|
332
|
+
|
333
|
+
def to_hash
|
334
|
+
h = super
|
335
|
+
h.delete(:time)
|
336
|
+
h
|
337
|
+
end
|
338
|
+
|
339
|
+
def method_missing(method, *args, &block)
|
340
|
+
# puts "&&&&& #{self.class}: method: #{method}"
|
341
|
+
# p caller[0]
|
342
|
+
if method == :to_s_junos
|
343
|
+
:to_s_default
|
344
|
+
else
|
345
|
+
super
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
protected
|
350
|
+
|
351
|
+
def csum_to_i
|
352
|
+
@_csum.unpack('n')[0]
|
353
|
+
rescue Exception => e
|
354
|
+
encode
|
355
|
+
retry
|
356
|
+
end
|
357
|
+
|
358
|
+
|
359
|
+
private
|
360
|
+
|
361
|
+
def csum=(value)
|
362
|
+
raise if value.is_a?(Fixnum)
|
363
|
+
@_csum=value
|
364
|
+
end
|
365
|
+
|
366
|
+
def refresh?(refresh_time)
|
367
|
+
ls_age.to_i > refresh_time
|
368
|
+
end
|
369
|
+
|
370
|
+
def seqn
|
371
|
+
@sequence_number
|
372
|
+
end
|
373
|
+
|
374
|
+
def validate_checksum(s)
|
375
|
+
if ! cheksum(s[2..-1], 0) == [0,0]
|
376
|
+
puts "*** checksum error ? #{cheksum(s[2..-1], 0)}"
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
#FIXME
|
381
|
+
def klass_to_ls_type
|
382
|
+
case self.class
|
383
|
+
when OSPFv2::Router ; 1
|
384
|
+
when OSPFv2::Network ; 2
|
385
|
+
when OSPFv2::Summary ; 3
|
386
|
+
# when AsExternal ; 5
|
387
|
+
else
|
388
|
+
raise
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
MODX=4102
|
393
|
+
|
394
|
+
def cheksum(mess, k=0)
|
395
|
+
len = mess.size
|
396
|
+
|
397
|
+
if (k>0)
|
398
|
+
mess[k-1] = [0].pack('C')
|
399
|
+
mess[k] = [0].pack('C')
|
400
|
+
end
|
401
|
+
|
402
|
+
c0,c1,n=0,0,0
|
403
|
+
|
404
|
+
s = mess.dup
|
405
|
+
while s.size>0 and n <= 4102 # MODX
|
406
|
+
n +=1
|
407
|
+
c0 += s.slice!(0,1).unpack('C')[0]
|
408
|
+
c1 +=c0
|
409
|
+
end
|
410
|
+
|
411
|
+
c0 = c0%255
|
412
|
+
c1 = c1%255
|
413
|
+
|
414
|
+
ip = (c1 <<8) + c0
|
415
|
+
|
416
|
+
if k>0
|
417
|
+
iq = ((len-k)*c0 - c1)%255 ; iq += 255 if (iq <= 0)
|
418
|
+
ir = (510 - c0 - iq) ; ir += -255 if (ir>255)
|
419
|
+
return [iq,ir]
|
420
|
+
else
|
421
|
+
[c0,c1]
|
422
|
+
end
|
423
|
+
|
424
|
+
end
|
425
|
+
|
426
|
+
end
|
427
|
+
|
428
|
+
end
|
429
|
+
|
430
|
+
load "../../../test/ospfv2/lsa/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|