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/summary.rb
ADDED
@@ -0,0 +1,393 @@
|
|
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
|
+
|
25
|
+
require 'ie/metric'
|
26
|
+
require 'ie/mt_metric'
|
27
|
+
require 'ie/id'
|
28
|
+
|
29
|
+
|
30
|
+
module OSPFv2
|
31
|
+
|
32
|
+
Netmask = Class.new(Id)
|
33
|
+
|
34
|
+
class Summary_Base < Lsa
|
35
|
+
|
36
|
+
attr_reader :metric, :netmask, :mt_metrics
|
37
|
+
|
38
|
+
def initialize(arg={})
|
39
|
+
@netmask=nil
|
40
|
+
@metric=nil
|
41
|
+
@mt_metrics=[]
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def mt_metrics=(val)
|
46
|
+
[val].flatten.each { |x| self << x }
|
47
|
+
end
|
48
|
+
|
49
|
+
def <<(metric)
|
50
|
+
@mt_metrics ||=[]
|
51
|
+
@mt_metrics << MtMetric.new(metric)
|
52
|
+
end
|
53
|
+
|
54
|
+
def encode
|
55
|
+
@netmask ||= Netmask.new
|
56
|
+
@metric ||= Metric.new
|
57
|
+
summary =[]
|
58
|
+
summary << netmask.encode
|
59
|
+
summary << metric.encode
|
60
|
+
summary << mt_metrics.collect { |x| x.encode } if mt_metrics
|
61
|
+
super summary.join
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(s)
|
65
|
+
netmask, metric, mt_metrics = super(s).unpack('NNa*')
|
66
|
+
@netmask = Netmask.new netmask
|
67
|
+
@metric = Metric.new metric
|
68
|
+
while mt_metrics.size>0
|
69
|
+
self << MtMetric.new(mt_metrics.slice!(0,4))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_hash
|
74
|
+
super
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s_default(*args)
|
78
|
+
super +
|
79
|
+
['',netmask, metric, *mt_metrics].collect { |x| x.to_s }.join("\n ")
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_s_junos_verbose
|
83
|
+
mask = "mask #{netmask.to_ip}"
|
84
|
+
super +
|
85
|
+
['', mask, metric.to_s_junos, *mt_metrics.collect{|m| m.to_s_junos}].join("\n ")
|
86
|
+
end
|
87
|
+
def to_s_junos
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class Summary < Summary_Base
|
94
|
+
class << self
|
95
|
+
def count
|
96
|
+
@count ||= 0
|
97
|
+
end
|
98
|
+
|
99
|
+
def incr_count
|
100
|
+
self.count
|
101
|
+
@count += 1
|
102
|
+
end
|
103
|
+
|
104
|
+
def reset
|
105
|
+
@count = nil
|
106
|
+
end
|
107
|
+
|
108
|
+
def base_ip_addr(addr=SUMMARY_BASE_ADDRESS)
|
109
|
+
@base_addr ||= IPAddr.new(addr)
|
110
|
+
end
|
111
|
+
|
112
|
+
def network
|
113
|
+
@base_addr + count
|
114
|
+
end
|
115
|
+
|
116
|
+
def new_lsdb(arg={})
|
117
|
+
new({:network=> base_ip_addr ^ incr_count}.merge(arg))
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def initialize(arg={})
|
124
|
+
if arg.is_a?(Hash)
|
125
|
+
arg = fix_hash(arg).merge!({:ls_type => :summary_lsa,})
|
126
|
+
end
|
127
|
+
super
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def fix_hash(arg)
|
133
|
+
if arg[:network]
|
134
|
+
addr = IPAddr.new arg[:network]
|
135
|
+
arg.delete :network
|
136
|
+
arg.store :netmask, addr.netmask
|
137
|
+
arg.store :ls_id, addr.to_s
|
138
|
+
end
|
139
|
+
arg
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
class AsbrSummary < Summary_Base
|
145
|
+
def initialize(arg={})
|
146
|
+
arg.merge!({:ls_type => :asbr_summary_lsa,}) if arg.is_a?(Hash)
|
147
|
+
super
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class Summary_Base
|
152
|
+
def self.new_hash(hash)
|
153
|
+
raise ArgumentError, "Invalid argument" unless hash.is_a?(Hash)
|
154
|
+
new(hash)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
load "../../../test/ospfv2/lsa/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
162
|
+
|
163
|
+
__END__
|
164
|
+
|
165
|
+
# if arg.is_a?(Hash)
|
166
|
+
# arg.merge!({:ls_type=> :summary_lsa}) unless arg.has_key?(:ls_type)
|
167
|
+
# set arg
|
168
|
+
# super
|
169
|
+
# elsif arg.is_a?(String)
|
170
|
+
# parse arg
|
171
|
+
# elsif arg.is_a?(self.class)
|
172
|
+
# parse arg.encode
|
173
|
+
# else
|
174
|
+
# raise ArgumentError, "Invalid argument", caller
|
175
|
+
# end
|
176
|
+
|
177
|
+
=begin rdoc
|
178
|
+
|
179
|
+
|
180
|
+
A.4.4 Summary-LSAs
|
181
|
+
|
182
|
+
Summary-LSAs are the Type 3 and 4 LSAs. These LSAs are originated
|
183
|
+
by area border routers. Summary-LSAs describe inter-area
|
184
|
+
destinations. For details concerning the construction of summary-
|
185
|
+
LSAs, see Section 12.4.3.
|
186
|
+
|
187
|
+
Type 3 summary-LSAs are used when the destination is an IP network.
|
188
|
+
In this case the LSA's Link State ID field is an IP network number
|
189
|
+
(if necessary, the Link State ID can also have one or more of the
|
190
|
+
network's "host" bits set; see Appendix E for details). When the
|
191
|
+
destination is an AS boundary router, a Type 4 summary-LSA is used,
|
192
|
+
and the Link State ID field is the AS boundary router's OSPF Router
|
193
|
+
ID. (To see why it is necessary to advertise the location of each
|
194
|
+
ASBR, consult Section 16.4.) Other than the difference in the Link
|
195
|
+
State ID field, the format of Type 3 and 4 summary-LSAs is
|
196
|
+
identical.
|
197
|
+
|
198
|
+
|
199
|
+
0 1 2 3
|
200
|
+
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
|
201
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
202
|
+
| LS age | Options | 3 or 4 |
|
203
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
204
|
+
| Link State ID |
|
205
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
206
|
+
| Advertising Router |
|
207
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
208
|
+
| LS sequence number |
|
209
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
210
|
+
| LS checksum | length |
|
211
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
212
|
+
| Network Mask |
|
213
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
214
|
+
| 0 | metric |
|
215
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
216
|
+
| TOS | TOS metric |
|
217
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
218
|
+
| ... |
|
219
|
+
|
220
|
+
|
221
|
+
For stub areas, Type 3 summary-LSAs can also be used to describe a
|
222
|
+
(per-area) default route. Default summary routes are used in stub
|
223
|
+
areas instead of flooding a complete set of external routes. When
|
224
|
+
describing a default summary route, the summary-LSA's Link State ID
|
225
|
+
is always set to DefaultDestination (0.0.0.0) and the Network Mask
|
226
|
+
is set to 0.0.0.0.
|
227
|
+
|
228
|
+
Network Mask
|
229
|
+
For Type 3 summary-LSAs, this indicates the destination
|
230
|
+
network's IP address mask. For example, when advertising the
|
231
|
+
location of a class A network the value 0xff000000 would be
|
232
|
+
used. This field is not meaningful and must be zero for Type 4
|
233
|
+
summary-LSAs.
|
234
|
+
|
235
|
+
metric
|
236
|
+
The cost of this route. Expressed in the same units as the
|
237
|
+
interface costs in the router-LSAs.
|
238
|
+
|
239
|
+
Additional TOS-specific information may also be included, for
|
240
|
+
backward compatibility with previous versions of the OSPF
|
241
|
+
specification ([Ref9]). For each desired TOS, TOS-specific
|
242
|
+
information is encoded as follows:
|
243
|
+
|
244
|
+
TOS IP Type of Service that this metric refers to. The encoding of
|
245
|
+
TOS in OSPF LSAs is described in Section 12.3.
|
246
|
+
|
247
|
+
TOS metric
|
248
|
+
TOS-specific metric information.
|
249
|
+
|
250
|
+
|
251
|
+
=end
|
252
|
+
|
253
|
+
|
254
|
+
module Ospf
|
255
|
+
module Summary_Shared
|
256
|
+
private
|
257
|
+
def __to_s_junos_style__(sum_type, rtype=' ')
|
258
|
+
enc
|
259
|
+
s = @header.to_s_junos_style(sum_type,rtype)
|
260
|
+
s +="\n mask #{netmask}"
|
261
|
+
s +="\n Topology default (ID #{@mt_id[0].id}) -> Metric: #{@mt_id[0].metric}"
|
262
|
+
s += @mt_id[1..-1].collect { |mt| "\n #{mt.to_s_junos_style}" }.join
|
263
|
+
s
|
264
|
+
end
|
265
|
+
def __to_hash__(sum_type)
|
266
|
+
enc
|
267
|
+
h = @header.to_hash.merge({:lsa_type=>sum_type, :netmask => netmask,})
|
268
|
+
if @mt_id.size > 1 or @mt_id[0].id != 0
|
269
|
+
h[:mt_id] = @mt_id.collect { |mt_id| mt_id.to_hash } unless @mt_id.nil?
|
270
|
+
else
|
271
|
+
h[:metric] = @mt_id[0].metric
|
272
|
+
end
|
273
|
+
h
|
274
|
+
end
|
275
|
+
private :__to_s_junos_style__, :__to_hash__
|
276
|
+
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
require 'lsa_header'
|
281
|
+
|
282
|
+
module Ospf
|
283
|
+
|
284
|
+
class SummaryLSAs < LSA
|
285
|
+
include Ospf
|
286
|
+
include Ospf::Ip
|
287
|
+
include Ospf::Summary_Shared
|
288
|
+
|
289
|
+
attr :header
|
290
|
+
attr_accessor :mt_id
|
291
|
+
|
292
|
+
def initialize(arg={})
|
293
|
+
@netmask, @mt_id = 0, []
|
294
|
+
if arg.is_a?(Hash) then
|
295
|
+
arg[:lstype]=3 if arg[:lstype].nil?
|
296
|
+
@header = LSA_Header.new(arg)
|
297
|
+
set(arg)
|
298
|
+
elsif arg.is_a?(String)
|
299
|
+
__parse(arg)
|
300
|
+
else
|
301
|
+
raise ArgumentError, "Invalid argument", caller
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def set(arg)
|
306
|
+
return self unless arg.is_a?(Hash)
|
307
|
+
@header.set(arg)
|
308
|
+
unless arg[:netmask].nil?
|
309
|
+
_netmask = arg[:netmask]
|
310
|
+
@netmask = _netmask.is_a?(String) ? ip2long(_netmask) : _netmask
|
311
|
+
end
|
312
|
+
|
313
|
+
unless arg[:metric].nil?
|
314
|
+
metric=arg[:metric]
|
315
|
+
@mt_id << MT.new({:metric=>metric})
|
316
|
+
end
|
317
|
+
unless arg[:mt_id].nil?
|
318
|
+
arg[:mt_id].each { |mt_id|
|
319
|
+
mt_id.is_a?(MT) ? @mt_id << mt_id : @mt_id << MT.new(mt_id)
|
320
|
+
}
|
321
|
+
end
|
322
|
+
self
|
323
|
+
end
|
324
|
+
|
325
|
+
def <<(arg)
|
326
|
+
append_metric(arg)
|
327
|
+
end
|
328
|
+
|
329
|
+
def enc
|
330
|
+
packet = @header.enc
|
331
|
+
packet+= __enc([[@netmask,'N'],])
|
332
|
+
packet +=@mt_id.collect {|mt_id| mt_id.enc}.join
|
333
|
+
packet_size(packet,@header)
|
334
|
+
packet_fletchsum(packet)
|
335
|
+
end
|
336
|
+
|
337
|
+
def __parse(s)
|
338
|
+
@header = LSA_Header.new(s)
|
339
|
+
arr = s[20..24].unpack("N")
|
340
|
+
@netmask = arr[0]
|
341
|
+
mt_ids = s[24..-1]
|
342
|
+
while mt_ids.size>0
|
343
|
+
@mt_id << MT.new(mt_ids.slice!(0,4))
|
344
|
+
end
|
345
|
+
end
|
346
|
+
private :__parse
|
347
|
+
|
348
|
+
def to_s
|
349
|
+
enc
|
350
|
+
s = @header.to_s
|
351
|
+
s += "\n netmask #{netmask}"
|
352
|
+
s += "\n " if @mt_id.size>0
|
353
|
+
s += @mt_id.collect { |mt| mt.to_s }.join("\n ")
|
354
|
+
end
|
355
|
+
|
356
|
+
def metric
|
357
|
+
@mt_id[0].metric
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
class SummaryLSA < SummaryLSAs
|
363
|
+
def initialize(arg={})
|
364
|
+
arg.merge!({:lstype => 3,}) if arg.is_a?(Hash)
|
365
|
+
super
|
366
|
+
end
|
367
|
+
def to_s_junos_style(rtype=' ')
|
368
|
+
__to_s_junos_style__('Summary', rtype)
|
369
|
+
end
|
370
|
+
def to_hash
|
371
|
+
__to_hash__('Summary')
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
class ASBR_SummaryLSA < SummaryLSAs
|
376
|
+
def initialize(arg={})
|
377
|
+
arg.merge!({:lstype => 4, :metric=>0}) if arg.is_a?(Hash)
|
378
|
+
super(arg)
|
379
|
+
end
|
380
|
+
def to_s_junos_style(rtype=' ')
|
381
|
+
__to_s_junos_style__('ASBRSum', rtype)
|
382
|
+
end
|
383
|
+
def to_hash
|
384
|
+
__to_hash__('ASBRSum')
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
if __FILE__ == $0
|
390
|
+
load '../test/lsa_summary_test.rb'
|
391
|
+
end
|
392
|
+
|
393
|
+
|
@@ -0,0 +1,298 @@
|
|
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
|
+
require 'thread'
|
25
|
+
require 'logger'
|
26
|
+
require 'infra/ospf_common'
|
27
|
+
require 'neighbor_sm/neighbor_state'
|
28
|
+
require 'infra/ospf_socket'
|
29
|
+
require 'infra/ospf_io'
|
30
|
+
require 'packet/ospf_packet'
|
31
|
+
require 'infra/timer'
|
32
|
+
require 'infra/ospf_constants'
|
33
|
+
require 'ls_db/link_state_database'
|
34
|
+
|
35
|
+
require 'neighbor/neighbor_event_handler'
|
36
|
+
|
37
|
+
module OSPFv2
|
38
|
+
|
39
|
+
class Neighbor
|
40
|
+
|
41
|
+
class Trace
|
42
|
+
def initialize(io=$stdout)
|
43
|
+
@logger = Logger.new(io)
|
44
|
+
end
|
45
|
+
def trace(s)
|
46
|
+
"{Time.to_ts} #{s}"
|
47
|
+
@logger << s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
include OSPFv2::Common
|
52
|
+
include OSPFv2::NeighborState
|
53
|
+
include OSPFv2
|
54
|
+
attr_reader :address, :inactivity_timer, :hello, :dd_rxmt_interval
|
55
|
+
|
56
|
+
InactivityTimer = Class.new(Timer)
|
57
|
+
HelloTimer = Class.new(PeriodicTimer)
|
58
|
+
RxmtIntervalTimer = Class.new(PeriodicTimer)
|
59
|
+
RefreshTimer = Class.new(PeriodicTimer)
|
60
|
+
RouterId = Class.new(Id)
|
61
|
+
AreadId = Class.new(Id)
|
62
|
+
|
63
|
+
attr_writer :hello_int, :dead_int
|
64
|
+
|
65
|
+
def initialize(arg={})
|
66
|
+
#TODO: accept prefix arg and set @address and @netmask in hello...
|
67
|
+
@address = arg[:src_addr] || '127.0.0.1'
|
68
|
+
@state = NeighborState::Down.new
|
69
|
+
@inactivity_timer = InactivityTimer.new(self.dead_int)
|
70
|
+
@periodic_hellos = HelloTimer.new(self.hello_int)
|
71
|
+
@router_id= RouterId.new arg[:router_id] || '1.1.1.1'
|
72
|
+
@area_id= AreaId.new arg[:aread_id] || '0.0.0.0'
|
73
|
+
@lsa_request_list = {}
|
74
|
+
@ls_db=nil
|
75
|
+
if arg[:log_fname]
|
76
|
+
@trace = Trace.new(arg[:log_fname])
|
77
|
+
else
|
78
|
+
@trace = Trace.new
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def hello_int
|
83
|
+
@hello_int ||= 10
|
84
|
+
end
|
85
|
+
def dead_int
|
86
|
+
@dead_int ||= hello_int*4
|
87
|
+
end
|
88
|
+
|
89
|
+
def state
|
90
|
+
@state.class.to_s.split('::').last.downcase.to_sym
|
91
|
+
end
|
92
|
+
|
93
|
+
def in_state?(*states)
|
94
|
+
if states.size==0
|
95
|
+
state
|
96
|
+
else
|
97
|
+
states.include? state
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def ls_db=(val)
|
102
|
+
raise ArgumentError, "expecting a LinkStateDatabase object!" unless val.is_a?(LSDB::LinkStateDatabase)
|
103
|
+
@ls_db=val
|
104
|
+
end
|
105
|
+
|
106
|
+
def log(ev, obj)
|
107
|
+
if obj.is_a?(String)
|
108
|
+
@trace.trace "\n#{Time.to_ts} #{ev}: #{obj}"
|
109
|
+
else
|
110
|
+
s = []
|
111
|
+
s << "\n#{Time.to_ts} (#{state}) #{ev} #{obj.name.to_camel}:\n#{obj}"
|
112
|
+
s << obj.encode.hexlify.join("\n ") if defined?($debug) and $debug == 1
|
113
|
+
s << "\n"
|
114
|
+
@trace.trace s.join
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def debug(obj)
|
119
|
+
log :debug, obj if defined? $debug and $debug ==1
|
120
|
+
end
|
121
|
+
|
122
|
+
def clear_lsa_request_list
|
123
|
+
@lsa_request_list={}
|
124
|
+
end
|
125
|
+
|
126
|
+
def router_id
|
127
|
+
hello.router_id
|
128
|
+
end
|
129
|
+
|
130
|
+
def change_state(new_state, event=nil)
|
131
|
+
@num ||=0
|
132
|
+
@num +=1
|
133
|
+
log 'state change', "#{@num}\# [#{event}]: #{state} -> #{new_state.class.to_s.split('::').last}"
|
134
|
+
@state = new_state
|
135
|
+
end
|
136
|
+
alias :new_state :change_state
|
137
|
+
|
138
|
+
def dd_sequence_number
|
139
|
+
@dd_sequence_number = DatabaseDescription.seqn
|
140
|
+
end
|
141
|
+
def start
|
142
|
+
unless @ev
|
143
|
+
@ev = NeighborEventHandler.new(self)
|
144
|
+
@evQ = Queue.new
|
145
|
+
end
|
146
|
+
@dd_rxmt_interval = RxmtIntervalTimer.new(5,@ev)
|
147
|
+
@periodic_rxmt = RxmtIntervalTimer.new(5,@ev)
|
148
|
+
@periodic_refresh = RefreshTimer.new(60,@ev)
|
149
|
+
init_sockets @address
|
150
|
+
init_io
|
151
|
+
start_io
|
152
|
+
start_periodic_hellos
|
153
|
+
@state.start(self)
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
def stop
|
158
|
+
debug "*** stopping #{router_id}"
|
159
|
+
@periodic_hellos.cancel
|
160
|
+
@periodic_rxmt.cancel
|
161
|
+
@periodic_refresh.cancel
|
162
|
+
stop_io
|
163
|
+
close_sockets
|
164
|
+
rescue Exception => e
|
165
|
+
debug "#{e} while stopping neighor"
|
166
|
+
ensure
|
167
|
+
@state.kill_nbr(self)
|
168
|
+
self
|
169
|
+
end
|
170
|
+
|
171
|
+
def update(*args)
|
172
|
+
@evQ.enq *args
|
173
|
+
end
|
174
|
+
def send(packet, dest=OSPFv2::AllSPFRouters)
|
175
|
+
return unless @output
|
176
|
+
[packet].flatten.each { |p|
|
177
|
+
log :snd, p
|
178
|
+
@output.enq [p,dest]
|
179
|
+
}
|
180
|
+
end
|
181
|
+
|
182
|
+
# AllSPFRouters = "224.0.0.5"
|
183
|
+
# AllDRouters = "224.0.0.6"
|
184
|
+
def flood(lsas, dest=AllSPFRouters)
|
185
|
+
# return unless @output
|
186
|
+
send (LinkStateUpdate.new_lsas lsas), dest
|
187
|
+
end
|
188
|
+
|
189
|
+
def start_periodic_hellos
|
190
|
+
@periodic_hellos.cancel
|
191
|
+
hh = {
|
192
|
+
:router_id=> @router_id,
|
193
|
+
:netmask=> 0xffffff00,
|
194
|
+
:designated_router_id=> '0.0.0.0',
|
195
|
+
:backup_designated_router_id=> '0.0.0.0',
|
196
|
+
:helloInt=>hello_int,
|
197
|
+
:options=>2,
|
198
|
+
:rtr_pri=>0,
|
199
|
+
:deadInt=>dead_int,
|
200
|
+
}
|
201
|
+
@hello = Hello.new(hh)
|
202
|
+
@periodic_hellos.start {
|
203
|
+
send(@hello)
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
def start_periodic_rxmt
|
208
|
+
debug "*** about to start periodic rxmt timer ***"
|
209
|
+
@periodic_rxmt.start {
|
210
|
+
if @ls_req_list
|
211
|
+
debug "There are #{@ls_req_list.size} LS Request to re-transmit!"
|
212
|
+
send LinkStateRequest.new :area_id => @area_id, :router_id=> @router_id, :requests=> @ls_req_list.keys \
|
213
|
+
unless @ls_req_list.empty?
|
214
|
+
end
|
215
|
+
if @ls_db
|
216
|
+
lsas = @ls_db.all_not_acked
|
217
|
+
debug "There are #{lsas.size} LSA to re-transmit!"
|
218
|
+
send LinkStateUpdate.new_lsas :router_id=> @router_id,
|
219
|
+
:area_id => @area_id, :lsas => lsas unless lsas.empty?
|
220
|
+
end
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
def start_ls_refresh
|
225
|
+
return unless @ls_db
|
226
|
+
debug "*** about to start periodic refresh timer ***"
|
227
|
+
@periodic_refresh.start {
|
228
|
+
@ls_db.refresh if in_state? :full, :loading, :exchange
|
229
|
+
}
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
def negotiation_done
|
235
|
+
@state.negotiation_done
|
236
|
+
end
|
237
|
+
def exchange_done
|
238
|
+
@state.exchange_done(self)
|
239
|
+
end
|
240
|
+
|
241
|
+
def send_dd(dd, rxmt=false)
|
242
|
+
dd_rxmt_interval.cancel
|
243
|
+
dd_rxmt_interval.start { debug "\n\n\n*** re-transmitting #{dd} ***\n\n\n" ; send dd } if rxmt
|
244
|
+
send dd, @neighbor_ip
|
245
|
+
@sent_dd = dd
|
246
|
+
end
|
247
|
+
|
248
|
+
def method_missing(method, *args, &block)
|
249
|
+
if method.to_s =~ /^(recv|unpack)/
|
250
|
+
puts %{
|
251
|
+
|
252
|
+
Method missing : #{method} !!!! #{@neighbor_state}
|
253
|
+
|
254
|
+
}
|
255
|
+
puts caller.reverse.join("\n")
|
256
|
+
raise
|
257
|
+
else
|
258
|
+
super
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def init_sockets(src_addr)
|
265
|
+
begin
|
266
|
+
@rsock = RecvSocket.new(src_addr)
|
267
|
+
@ssock = SendSocket.new(src_addr)
|
268
|
+
rescue(Errno::EPERM) => e
|
269
|
+
STDERR.puts "\n**** root permission required, neighbor cannot be started.\n"
|
270
|
+
return
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def close_sockets
|
275
|
+
@rsock.close
|
276
|
+
@ssock.close
|
277
|
+
rescue
|
278
|
+
end
|
279
|
+
|
280
|
+
def init_io
|
281
|
+
@input = Input.new(@rsock,self, @ev)
|
282
|
+
@output = OutputQ.new(@ssock,self, @ev)
|
283
|
+
end
|
284
|
+
def start_io
|
285
|
+
@input.start
|
286
|
+
@output.start
|
287
|
+
end
|
288
|
+
def stop_io
|
289
|
+
@input.stop
|
290
|
+
@output.stop
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
require 'neighbor/recv_ospf_packet'
|
298
|
+
|