ospfv2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/bin/ospfv2 +136 -0
  2. data/lib/ie/au_type.rb +79 -0
  3. data/lib/ie/external_route.rb +181 -0
  4. data/lib/ie/id.rb +97 -0
  5. data/lib/ie/interface_mtu.rb +64 -0
  6. data/lib/ie/ls_age.rb +89 -0
  7. data/lib/ie/ls_type.rb +148 -0
  8. data/lib/ie/metric.rb +63 -0
  9. data/lib/ie/mt_metric.rb +119 -0
  10. data/lib/ie/options.rb +356 -0
  11. data/lib/ie/ospf_version.rb +67 -0
  12. data/lib/ie/packet_type.rb +65 -0
  13. data/lib/ie/router_link.rb +167 -0
  14. data/lib/ie/router_link_factory.rb +53 -0
  15. data/lib/ie/router_link_type.rb +86 -0
  16. data/lib/ie/sequence_number.rb +144 -0
  17. data/lib/ie/tos_metric.rb +102 -0
  18. data/lib/infra/ospf_common.rb +291 -0
  19. data/lib/infra/ospf_constants.rb +73 -0
  20. data/lib/infra/ospf_io.rb +133 -0
  21. data/lib/infra/ospf_socket.rb +126 -0
  22. data/lib/infra/parse_options.rb +135 -0
  23. data/lib/infra/timer.rb +104 -0
  24. data/lib/infra/to_s.rb +38 -0
  25. data/lib/ls_db/advertised_routers.rb +78 -0
  26. data/lib/ls_db/common.rb +31 -0
  27. data/lib/ls_db/link_state_database.rb +376 -0
  28. data/lib/ls_db/link_state_database_build.rb +181 -0
  29. data/lib/ls_db/link_state_database_links.rb +178 -0
  30. data/lib/ls_db/links.rb +160 -0
  31. data/lib/lsa/external.rb +347 -0
  32. data/lib/lsa/lsa.rb +438 -0
  33. data/lib/lsa/lsa_factory.rb +59 -0
  34. data/lib/lsa/network.rb +166 -0
  35. data/lib/lsa/router.rb +336 -0
  36. data/lib/lsa/summary.rb +393 -0
  37. data/lib/neighbor/neighbor.rb +298 -0
  38. data/lib/neighbor/neighbor_event_handler.rb +61 -0
  39. data/lib/neighbor/recv_database_description.rb +153 -0
  40. data/lib/neighbor/recv_hello.rb +53 -0
  41. data/lib/neighbor/recv_ospf_packet.rb +68 -0
  42. data/lib/neighbor_sm/attempt_state.rb +44 -0
  43. data/lib/neighbor_sm/down_state.rb +46 -0
  44. data/lib/neighbor_sm/exchange_state.rb +32 -0
  45. data/lib/neighbor_sm/exstart_state.rb +69 -0
  46. data/lib/neighbor_sm/full_state.rb +36 -0
  47. data/lib/neighbor_sm/init_state.rb +43 -0
  48. data/lib/neighbor_sm/loading_state.rb +33 -0
  49. data/lib/neighbor_sm/neighbor_state.rb +87 -0
  50. data/lib/packet/database_description.rb +300 -0
  51. data/lib/packet/hello.rb +327 -0
  52. data/lib/packet/link_state_ack.rb +144 -0
  53. data/lib/packet/link_state_request.rb +153 -0
  54. data/lib/packet/link_state_update.rb +189 -0
  55. data/lib/packet/ospf_packet.rb +306 -0
  56. metadata +116 -0
@@ -0,0 +1,376 @@
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
+
25
+ =begin rdoc
26
+
27
+ 12.2. The link state database
28
+
29
+ A router has a separate link state database for every area to
30
+ which it belongs. All routers belonging to the same area have
31
+ identical link state databases for the area.
32
+
33
+ The databases for each individual area are always dealt with
34
+ separately. The shortest path calculation is performed
35
+ separately for each area (see Section 16). Components of the
36
+ area link-state database are flooded throughout the area only.
37
+ Finally, when an adjacency (belonging to Area A) is being
38
+ brought up, only the database for Area A is synchronized between
39
+ the two routers.
40
+
41
+ The area database is composed of router-LSAs, network-LSAs and
42
+ summary-LSAs (all listed in the area data structure). In
43
+ addition, external routes (AS-external-LSAs) are included in all
44
+ non-stub area databases (see Section 3.6).
45
+
46
+ An implementation of OSPF must be able to access individual
47
+ pieces of an area database. This lookup function is based on an
48
+ LSA's LS type, Link State ID and Advertising Router.[14] There
49
+ will be a single instance (the most up-to-date) of each LSA in
50
+ the database. The database lookup function is invoked during
51
+ the LSA flooding procedure (Section 13) and the routing table
52
+ calculation (Section 16). In addition, using this lookup
53
+ function the router can determine whether it has itself ever
54
+ originated a particular LSA, and if so, with what LS sequence
55
+ number.
56
+
57
+ An LSA is added to a router's database when either a) it is
58
+ received during the flooding process (Section 13) or b) it is
59
+ originated by the router itself (Section 12.4). An LSA is
60
+ deleted from a router's database when either a) it has been
61
+ overwritten by a newer instance during the flooding process
62
+ (Section 13) or b) the router originates a newer instance of one
63
+ of its self-originated LSAs (Section 12.4) or c) the LSA ages
64
+ out and is flushed from the routing domain (Section 14).
65
+ Whenever an LSA is deleted from the database it must also be
66
+ removed from all neighbors' Link state retransmission lists (see
67
+ Section 10).
68
+
69
+ =end
70
+
71
+ require 'set'
72
+ require 'ie/id'
73
+ require 'lsa/lsa_factory'
74
+ require 'ls_db/common'
75
+ require 'ls_db/advertised_routers'
76
+
77
+ require 'infra/to_s'
78
+
79
+ module OSPFv2
80
+
81
+ module LSDB
82
+
83
+ class LinkStateDatabase
84
+ include OSPFv2
85
+ include OSPFv2::Common
86
+ include TO_S
87
+
88
+ AreaId = Class.new(OSPFv2::Id)
89
+
90
+ attr_reader :area_id
91
+ attr_writer_delegate :area_id
92
+
93
+ attr_reader :advertised_routers
94
+ attr_accessor :offset, :ls_refresh_interval
95
+
96
+ def initialize(arg={})
97
+ @ls_db = Hash.new
98
+ @area_id = nil
99
+ @advertised_routers= AdvertisedRouters.new
100
+ @ls_refresh_interval=180
101
+ @offset=0
102
+ set arg
103
+ end
104
+
105
+ def ls_refresh_time
106
+ @ls_refresh_time ||= LSRefreshTime
107
+ end
108
+
109
+ def ls_refresh_time=(val)
110
+ @ls_refresh_time=val
111
+ end
112
+
113
+ def proxied?(router_id)
114
+ advertised_routers.has?(router_id)
115
+ end
116
+
117
+ def all
118
+ @ls_db.values
119
+ end
120
+ alias :lsas :all
121
+
122
+ #TODO: add opaque and external type 7
123
+ LsType.all.each do |type|
124
+ define_method("all_#{type}") do
125
+ @ls_db.find_all { |k,v| k[0]== LsType.to_i(type) }.collect { |k,v| v }.sort_by { |l| l.advertising_router.to_i }
126
+ end
127
+ end
128
+
129
+ def all_proxied
130
+ @ls_db.values.find_all { |lsa| advertised_routers.has? lsa.advertising_router }
131
+ end
132
+
133
+ def each
134
+ @ls_db.values.each do |lsa|
135
+ yield lsa
136
+ end
137
+ end
138
+
139
+ def ls_db=(arg)
140
+ [arg].flatten.each { |l| self << l }
141
+ end
142
+
143
+ def keys
144
+ @ls_db.keys
145
+ end
146
+
147
+ def <<(lsa)
148
+ lsa = OSPFv2::Lsa.factory(lsa) unless lsa.is_a?(Lsa)
149
+ @ls_db.store(lsa.key,lsa)
150
+ lsa
151
+ end
152
+
153
+ def ls_ack(lsa)
154
+
155
+ lsa = lookup(lsa)
156
+ if lsa
157
+ if lsa.maxaged?
158
+ @ls_db.delete(lsa.key)
159
+ else
160
+ @ls_db[lsa.key].ack
161
+ end
162
+ end
163
+
164
+ end
165
+
166
+ def to_hash
167
+ h= { :area=> @area_id.to_ip }
168
+ h.store :ls_db, @ls_db.sort.collect {|p| p[1].to_hash }
169
+ h.store :advertised_routers, advertised_routers.routers
170
+ h.store :ls_refresh_time, ls_refresh_time
171
+ h.store :ls_refresh_interval, ls_refresh_interval
172
+
173
+ # h.store(:retransmit,@retransmit)
174
+ # h.store(:ls_rxmt_interval,@ls_rxmt_interval)
175
+ # h.store(:aging,self.aging)
176
+ h
177
+ end
178
+
179
+ def find_router_lsa(router_id)
180
+ lookup(1,router_id)
181
+ end
182
+ def find_asbr_sum(advertising_router)
183
+ lookup(4,advertising_router)
184
+ end
185
+
186
+ def lookup(*args)
187
+ if args.size==1
188
+ if args[0].is_a?(Array) and args[0].size==3
189
+ if args[0][0].is_a?(Symbol)
190
+ args[0][0] = LsType.to_i(args[0][0])
191
+ end
192
+ args[0][1] = id2i(args[0][1])
193
+ args[0][2] = id2i(args[0][2])
194
+ # lsdb.lookup([type,lsid,advr])
195
+ # self[args[0]]
196
+ @ls_db[args[0]]
197
+ elsif args[0].is_a?(Lsa)
198
+ # ls_db.lookup(lsa)
199
+ @ls_db[args[0].key]
200
+ else
201
+ raise ArgumentError, "Invalid argument, #{args.inspect}"
202
+ end
203
+ elsif args.size==3
204
+ # lsdb.lookup(type, lsid, advr)
205
+ lookup(args)
206
+ elsif args.size==2
207
+ # lsdb.lookup(type, lsid, lsid)
208
+ lookup([args[0],args[1],args[1]])
209
+ else
210
+ raise ArgumentError, "*** Invalid argument, #{args.inspect}"
211
+ end
212
+ end
213
+
214
+
215
+ def refresh
216
+ all.find_all {|l| l.refresh(ls_refresh_time) }
217
+ end
218
+
219
+ def reset
220
+ each {|lsa| lsa.ack }
221
+ @offset=0
222
+ end
223
+
224
+ def to_s_default
225
+ s = []
226
+ s << " OSPF link state database, Area #{area_id.to_ip}"
227
+ s << "Age Options Type Link-State ID Advr Router Sequence Checksum Length"
228
+ LsType.all.each do |type|
229
+ s << (__send__ "all_#{type}").collect { |l| l.to_s }
230
+ end
231
+ s.join("\n")
232
+ end
233
+
234
+ def to_s_junos(verbose=false)
235
+ lsas = []
236
+ lsas << " OSPF link state database, Area #{area_id.to_ip}"
237
+ lsas << " Type ID Adv Rtr Seq Age Opt Cksum Len "
238
+ LsType.all.each do |type|
239
+ lsas << " OSPF AS SCOPE link state database" if type == :external
240
+ lsas << (__send__ "all_#{type}").collect { |l|
241
+ if verbose
242
+ l.to_s_junos_verbose
243
+ else
244
+ l.to_s_junos
245
+ end
246
+ }
247
+ end
248
+ lsas.join("\n")
249
+ end
250
+ alias :to_j :to_s_junos
251
+
252
+ def [](*key)
253
+ lookup(*key)
254
+ end
255
+
256
+ def size
257
+ @ls_db.size
258
+ end
259
+
260
+ def all_not_acked
261
+ all.find_all { |l| ! l.ack? }
262
+ end
263
+
264
+ def method_missing(method, *args, &block)
265
+ super
266
+ end
267
+
268
+ def refresh
269
+ all.find_all {|l| l.refresh(advertised_routers, ls_refresh_time) }
270
+ end
271
+
272
+ def ls_refresh?(ls)
273
+ rt = ls_refresh_time
274
+ ls.instance_eval { refresh?(rt) }
275
+ end
276
+
277
+ def recv_link_state_update(link_state_update)
278
+ link_state_update.each do |lsa|
279
+ if advertised_routers.has?(lsa.advertising_router)
280
+ if @ls_db.key? lsa.key
281
+ @ls_db[lsa.key].force_refresh(lsa.sequence_number)
282
+ else
283
+ @ls_db.store(lsa.key,lsa)
284
+ lsa.maxage
285
+ end
286
+ else
287
+ if lsa.maxaged?
288
+ @ls_db.delete lsa.key
289
+ else
290
+ @ls_db.store(lsa.key,lsa)
291
+ # TBD: remove lsa from lsr_list
292
+ end
293
+ end
294
+ end
295
+ end
296
+
297
+ def has?(obj)
298
+ lookup(obj)
299
+ end
300
+
301
+
302
+ def recv_dd(dd, ls_req_list)
303
+ raise ArgumentError, "lss nil" unless ls_req_list
304
+ dd.each { |dd_lsa|
305
+ if advertised_routers.has?(dd_lsa.advertising_router)
306
+ our_lsa = lookup(dd_lsa)
307
+ if our_lsa and (our_lsa <=> dd_lsa)
308
+ our_lsa.force_refresh(dd_lsa.sequence_number)
309
+ end
310
+ else
311
+ ls_req_list.store(dd_lsa.key,0)
312
+ end
313
+ }
314
+ nil
315
+ end
316
+
317
+ private
318
+
319
+ def lsa_types
320
+ [:router, :network, :summary, :asbr_summary, :as_external]
321
+ end
322
+
323
+ def id2i(id)
324
+ return id if id.is_a?(Integer)
325
+ IPAddr.new(id).to_i
326
+ end
327
+ def id2ip(id)
328
+ return id if id.is_a?(String)
329
+ IPAddr.create(id).to_s
330
+ end
331
+
332
+ end
333
+
334
+ #
335
+ # @ls_db = []
336
+ # @ls_db << {
337
+ # :sequence_number=>2147483650,
338
+ # :advertising_router=>"1.2.0.0",
339
+ # :ls_id=>"0.0.4.5",
340
+ # :nwveb=>1,
341
+ # :ls_type=>:router_lsa,
342
+ # :options=> 0x21,
343
+ # :ls_age=>10,
344
+ # :links=>[
345
+ # {
346
+ # :link_id=>"1.1.1.1",
347
+ # :link_data=>"255.255.255.255",
348
+ # :router_link_type=>:point_to_point,
349
+ # :metric=>11,
350
+ # :mt_metrics=>[ {:id=>1, :metric=>11}, {:id=>2, :metric=>22} ]
351
+ # },
352
+ # {
353
+ # :link_id=>"1.1.1.2",
354
+ # :link_data=>"255.255.255.255",
355
+ # :router_link_type=>:point_to_point,
356
+ # :metric=>12,
357
+ # :mt_metrics=>[]
358
+ # }
359
+ # ],
360
+ # }
361
+ #
362
+ #
363
+ # ls_db = LinkStateDatabase.new :area_id=> 1, :ls_db => @ls_db
364
+ # puts ""
365
+ # puts ls_db.to_s_junos
366
+ #
367
+
368
+
369
+
370
+ end
371
+ end
372
+
373
+ require 'ls_db/link_state_database_build'
374
+
375
+ load "../../../test/ospfv2/ls_db/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
376
+
@@ -0,0 +1,181 @@
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 'set'
25
+ require 'ie/id'
26
+ require 'ls_db/links'
27
+
28
+ require 'ls_db/link_state_database'
29
+
30
+ module OSPFv2::LSDB
31
+ class LinkStateDatabase
32
+ include OSPFv2
33
+ include OSPFv2::Common
34
+
35
+
36
+ def add_adjacency(*arg)
37
+
38
+ if arg.size==1 and arg[0].is_a?(Hash)
39
+ arg = arg[0]
40
+ router_id = arg[:router_id]
41
+ neighbor_id = arg[:neighbor_router_id]
42
+ prefix = arg[:prefix]
43
+ metric = arg[:metric] ||= 1
44
+ link = arg[:link] if arg[:link] and arg[:link].is_a?(Link)
45
+ elsif arg.size>2
46
+ router_id, neighbor_id, prefix, metric = arg
47
+ metric ||=1
48
+ else
49
+ raise ArgumentError
50
+ end
51
+
52
+ raise ArgumentError, "missing prefix" unless prefix
53
+ raise ArgumentError, "missing neighbor router id" unless neighbor_id
54
+
55
+ _, addr, plen, network, netmask = IPAddr.to_ary(prefix)
56
+
57
+ # if not set assume router id is the interface address given to us in :prefix
58
+ router_id ||= addr
59
+
60
+
61
+ # router_id to list of advertised routers
62
+ advertised_routers + router_id
63
+
64
+ rlsa = find_router_lsa router_id
65
+
66
+ if ! rlsa
67
+
68
+ # We need to build a router lsa
69
+ rlsa = OSPFv2::Lsa.factory \
70
+ :advertising_router=> router_id,
71
+ :ls_id=> router_id,
72
+ :ls_type=>:router_lsa,
73
+ :options=> 0x22
74
+
75
+ advertised_routers + router_id
76
+
77
+ # add to lsdb
78
+ self << rlsa
79
+
80
+ else
81
+
82
+ # delete any exisiting p2p and stub network
83
+ rlsa.delete(1,neighbor_id)
84
+ rlsa.delete(3,network)
85
+
86
+ end
87
+
88
+ # Add a new router-link and stub network that describes the adjacency
89
+ rlsa << { :link_id=>neighbor_id, :link_data=>addr, :router_link_type=>:point_to_point, :metric=>metric, }
90
+ rlsa << { :link_id=>network, :link_data=>netmask, :router_link_type=>:stub_network, :metric=>metric }
91
+
92
+ rlsa
93
+
94
+ end
95
+ alias :add_p2p_adjacency :add_adjacency
96
+
97
+
98
+ def remove_adjacency(rid, neighbor_id, prefix)
99
+ if (rlsa = lookup(:router_lsa, rid))
100
+ addr, source_address, plen, network, netmask = IPAddr.to_ary(prefix)
101
+ rlsa.delete(:point_to_point,id2ip(neighbor_id))
102
+ rlsa.delete(3,network)
103
+ end
104
+ rlsa
105
+ end
106
+
107
+ # :router_id=> 1, :link_id=> '192.168.0.1', :link_data => '255.255.255.255'
108
+ # :router_id=> 1, :network=> '192.168.0.1/24', :metric => 10
109
+ def add_link_to_stub_network(arg={})
110
+
111
+ router_id = arg[:router_id]
112
+ link_id = arg[:link_id]
113
+ link_data = arg[:link_data]
114
+
115
+ if arg[:network]
116
+ addr = IPAddr.new arg[:network]
117
+ link_id = addr.to_s
118
+ link_data = addr.netmask
119
+ end
120
+
121
+ raise ArgumentError, "missing neighbor router id" unless router_id
122
+ raise ArgumentError, "missing neighbor link_id" unless link_id
123
+ raise ArgumentError, "missing neighbor link_data" unless link_data
124
+
125
+ metric = arg[:metric] ||=0
126
+
127
+ # link = arg[:link] if arg[:link] and arg[:link].is_a?(RouterLink)
128
+
129
+ rlsa = find_router_lsa(router_id)
130
+
131
+ link = {:router_link_type=>:stub_network, :metric=>metric, :link_id=>link_id, :link_data=>link_data}
132
+ if ! rlsa
133
+
134
+ # build a router lsa with a stub network
135
+ rlsa = OSPFv2::Lsa.factory \
136
+ :advertising_router=> router_id,
137
+ :ls_id=> router_id,
138
+ :nwveb=>2,
139
+ :ls_type=>:router_lsa,
140
+ :options=> 0x22
141
+
142
+ advertised_routers + router_id
143
+
144
+ # add to lsdb
145
+ self << rlsa
146
+
147
+ end
148
+
149
+ # replace or add new stub router link
150
+ rlsa = find_router_lsa(router_id)
151
+ rlsa.delete(3,link_id)
152
+ rlsa << link
153
+ rlsa
154
+ end
155
+
156
+ #
157
+ # Router ID: 13.11.13.11
158
+ #
159
+ # Router *13.11.13.11 13.11.13.11 0x80000022 458 0x22 0x58e9 36
160
+ # bits 0x0, link count 1
161
+ # id 192.168.1.200, data 192.168.1.200, Type Transit (2)
162
+ # Topology count: 0, Default metric: 10
163
+ #
164
+ def add_router_id(router_id)
165
+ add_link_to_stub_network :router_id => router_id, :link_id=> router_id, :link_data=> router_id
166
+ end
167
+
168
+ # Router *13.11.13.11 13.11.13.11 0x80000032 16 0x22 0xf55e 48
169
+ # bits 0x0, link count 1
170
+ # id 99.99.1.1, data 255.255.255.255, Type Stub (3)
171
+ # Topology count: 0, Default metric: 0
172
+ #
173
+ def add_loopback(arg={})
174
+ add_link_to_stub_network :router_id => arg[:router_id], :link_id=> arg[:address], :link_data=> '255.255.255.255', :metric=> arg[:metric]
175
+ end
176
+
177
+ end
178
+
179
+ end
180
+
181
+ load "../../../test/ospfv2/ls_db/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0