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.
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