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
@@ -0,0 +1,178 @@
|
|
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 'ls_db/link_state_database'
|
24
|
+
require 'ls_db/links'
|
25
|
+
require 'lsa/lsa'
|
26
|
+
|
27
|
+
module OSPFv2
|
28
|
+
|
29
|
+
|
30
|
+
class Lsa
|
31
|
+
def lsdb_link_id
|
32
|
+
@_lsdb_link_id
|
33
|
+
end
|
34
|
+
def lsdb_link_id=(val)
|
35
|
+
@_lsdb_link_id= val
|
36
|
+
end
|
37
|
+
def find_lsa_from_link(id)
|
38
|
+
all.find_all { |l| l.lsdb_link_id==id }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
module OSPFv2::LSDB
|
45
|
+
|
46
|
+
class LinkStateDatabase
|
47
|
+
|
48
|
+
def self.router_id(row, col, base_rid=ROUTER_ID_BASE)
|
49
|
+
(row << 16) + col + base_rid
|
50
|
+
end
|
51
|
+
|
52
|
+
def router_id(*args)
|
53
|
+
LinkStateDatabase.router_id(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
# lsdb = LinkStateDatabase.create 10, 10, :prefix => '192.168.0.0/24'
|
57
|
+
# lsdb = LinkStateDatabase.create 10, 10, :prefix_base => '192.168.0.0/24', :router_id_base =>
|
58
|
+
def self.create(arg={})
|
59
|
+
arg = {:area_id=> 0, :columns=>2, :rows=>2, :base_router_id=> 0, :base_prefix=>'172.21.0.0/30'}.merge(arg)
|
60
|
+
ls_db = new arg
|
61
|
+
rows=arg[:rows]
|
62
|
+
cols=arg[:columns]
|
63
|
+
@base_router_id = arg[:base_router_id]
|
64
|
+
if arg[:base_prefix]
|
65
|
+
Link.reset_ip_addr
|
66
|
+
Link.base_ip_addr arg[:base_prefix]
|
67
|
+
end
|
68
|
+
@base_prefix = arg[:base_prefix]
|
69
|
+
router_id = lambda { |c,r| (r<<16) + c + @base_router_id }
|
70
|
+
1.upto(rows) do |r|
|
71
|
+
1.upto(cols) do |c|
|
72
|
+
ls_db.new_link(:router_id=> router_id.call(c,r-1), :neighbor_id=> router_id.call(c,r)) if r > 1
|
73
|
+
ls_db.new_link(:router_id=> router_id.call(c-1,r), :neighbor_id=> router_id.call(c,r)) if c > 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
ls_db
|
77
|
+
end
|
78
|
+
|
79
|
+
# link, :dir => :local_only
|
80
|
+
# link_hash, :direction => :remote_only
|
81
|
+
|
82
|
+
def new_link(*args)
|
83
|
+
|
84
|
+
# get a link object
|
85
|
+
local, remote = true, true
|
86
|
+
if args.size==1 and args[0].is_a?(Hash)
|
87
|
+
link = Link.new args[0]
|
88
|
+
elsif args[0].is_a?(Link)
|
89
|
+
link = args[0]
|
90
|
+
else
|
91
|
+
raise ArgumentError, "invalid argument: #{args.inspect}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# local, remote or both
|
95
|
+
dir = args[0][:direction] ||= :both
|
96
|
+
local = false if dir and dir == :remote_only
|
97
|
+
remote = false if dir and dir == :local_only
|
98
|
+
|
99
|
+
if local
|
100
|
+
lsa = add_p2p_adjacency :router_id => link.router_id.to_i, :neighbor_router_id => link.neighbor_id.to_i, :prefix => link.local_prefix, :metric=>1
|
101
|
+
lsa.lsdb_link_id = link.id
|
102
|
+
link.local_lsa = lsa.key
|
103
|
+
end
|
104
|
+
|
105
|
+
if remote
|
106
|
+
lsa = add_p2p_adjacency :router_id => link.neighbor_id.to_i, :neighbor_router_id => link.router_id.to_i, :prefix => link.remote_prefix, :metric=>1
|
107
|
+
lsa.lsdb_link_id = link.id
|
108
|
+
link.remote_lsa = lsa.key
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
def link(link, action)
|
114
|
+
raise ArgumentError, "invalid argument: #{link.class}" unless link.is_a?(Link)
|
115
|
+
case action
|
116
|
+
when :up ; link_up(link)
|
117
|
+
when :down ; link_down(link)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def link_up(link)
|
122
|
+
raise ArgumentError, "invalid argument: #{link.class}" unless link.is_a?(Link)
|
123
|
+
add_adjacency :router_id=> link.router_id.to_i,
|
124
|
+
:neighbor_router_id => link.neighbor_id.to_i,
|
125
|
+
:prefix=> link.local_prefix,
|
126
|
+
:metric => link.metric
|
127
|
+
add_adjacency :router_id=> link.neighbor_id.to_i,
|
128
|
+
:neighbor_router_id => link.router_id.to_i,
|
129
|
+
:prefix=> link.remote_prefix,
|
130
|
+
:metric => link.metric
|
131
|
+
end
|
132
|
+
|
133
|
+
def link_down(link)
|
134
|
+
lsa = @ls_db[link.local_lsa]
|
135
|
+
lsa.delete(1, link.neighbor_id.to_ip)
|
136
|
+
lsa = @ls_db[link.remote_lsa]
|
137
|
+
lsa.delete(1, link.router_id.to_ip)
|
138
|
+
end
|
139
|
+
|
140
|
+
def link_refresh
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
def link_maxage
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
# @ls_db = LinkStateDatabase.new :area_id=>0
|
151
|
+
# @ls_db.new_link :router_id=> 1, :neighbor_id=>2
|
152
|
+
# @ls_db.new_link :router_id=> 1, :neighbor_id=>3
|
153
|
+
# @ls_db.new_link :router_id=> 1, :neighbor_id=>4
|
154
|
+
# @ls_db.new_link :router_id=> 1, :neighbor_id=>5
|
155
|
+
#
|
156
|
+
# puts @ls_db
|
157
|
+
#
|
158
|
+
# # p Link[1]
|
159
|
+
#
|
160
|
+
# rlsa = @ls_db[1,1]
|
161
|
+
# p rlsa.links.size
|
162
|
+
# p rlsa
|
163
|
+
# rlsa.delete(:point_to_point,'0.0.0.2')
|
164
|
+
# p rlsa.links.size
|
165
|
+
#
|
166
|
+
# rlsa = @ls_db[1,2]
|
167
|
+
# p rlsa.links.size
|
168
|
+
# p rlsa
|
169
|
+
# rlsa.delete(:point_to_point,'0.0.0.1')
|
170
|
+
# p rlsa.links.size
|
171
|
+
#
|
172
|
+
# puts @ls_db
|
173
|
+
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
load "../../../test/ospfv2/ls_db/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
178
|
+
|
data/lib/ls_db/links.rb
ADDED
@@ -0,0 +1,160 @@
|
|
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 'infra/ospf_common'
|
24
|
+
require 'ie/id'
|
25
|
+
require 'ie/metric'
|
26
|
+
require 'ie/mt_metric'
|
27
|
+
require 'ls_db/common'
|
28
|
+
|
29
|
+
module OSPFv2::LSDB
|
30
|
+
|
31
|
+
class Link
|
32
|
+
|
33
|
+
class << self
|
34
|
+
|
35
|
+
def <<(val)
|
36
|
+
@_links ||={}
|
37
|
+
@_links.store(val.id, val)
|
38
|
+
end
|
39
|
+
|
40
|
+
def all
|
41
|
+
@_links ||={}
|
42
|
+
@_links
|
43
|
+
end
|
44
|
+
|
45
|
+
def ids
|
46
|
+
@_links ||={}
|
47
|
+
@_links.keys
|
48
|
+
end
|
49
|
+
|
50
|
+
def count
|
51
|
+
@count ||= 0
|
52
|
+
end
|
53
|
+
|
54
|
+
def incr_count
|
55
|
+
self.count
|
56
|
+
@count += 1
|
57
|
+
end
|
58
|
+
|
59
|
+
def reset
|
60
|
+
@_links={}
|
61
|
+
@count = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
def base_ip_addr(addr=LINK_BASE_ADDRESS)
|
65
|
+
@base_addr ||= IPAddr.new(addr)
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_by_id(router_id)
|
69
|
+
all.find_all { |k,v| v.router_id.to_ip == router_id }
|
70
|
+
end
|
71
|
+
|
72
|
+
def reset_ip_addr
|
73
|
+
@base_addr=nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def [](val)
|
77
|
+
@_links[val]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
include OSPFv2::Common
|
83
|
+
|
84
|
+
#FIXME: all IE should be in an IE namespace
|
85
|
+
RouterId = Class.new(OSPFv2::Id)
|
86
|
+
NeighborId = Class.new(OSPFv2::Id)
|
87
|
+
|
88
|
+
attr_reader :router_id, :neighbor_id, :metric
|
89
|
+
|
90
|
+
#TODO: :metric => [10,20] ... revisit
|
91
|
+
# :metric_ifa => 10, :metric_ifb=>20
|
92
|
+
def initialize(arg={})
|
93
|
+
@_state = :down
|
94
|
+
@_id = self.class.incr_count
|
95
|
+
@prefix=nil
|
96
|
+
@router_id= RouterId.new arg[:router_id] || '1.1.1.1'
|
97
|
+
@neighbor_id= NeighborId.new arg[:neighbor_id] || '2.2.2.2'
|
98
|
+
@metric = 0
|
99
|
+
set arg
|
100
|
+
@lsas=[]
|
101
|
+
Link << self
|
102
|
+
self
|
103
|
+
end
|
104
|
+
[:local, :remote].each_with_index { |n,i|
|
105
|
+
define_method("#{n}_prefix") do
|
106
|
+
instance_variable_set("@_#{n}_prefix", _address_(i+1))
|
107
|
+
end
|
108
|
+
}
|
109
|
+
|
110
|
+
def id
|
111
|
+
@_id
|
112
|
+
end
|
113
|
+
|
114
|
+
attr_reader :local_lsa, :remote_lsa
|
115
|
+
|
116
|
+
def local_lsa=(lsa)
|
117
|
+
@local_lsa=lsa
|
118
|
+
end
|
119
|
+
|
120
|
+
def remote_lsa=(lsa)
|
121
|
+
@remote_lsa=lsa
|
122
|
+
end
|
123
|
+
|
124
|
+
def network
|
125
|
+
@network ||=IPAddr.new(Link.base_ip_addr.^(@_id-1))
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_s
|
129
|
+
rid = router_id.to_s.split(":")
|
130
|
+
nid = neighbor_id.to_s.split(":")
|
131
|
+
sprintf("%3d\# %s: %-15.15s %s:%-15.15s Network %-15.15s %s",
|
132
|
+
@_id, rid[0], rid[1], nid[0], nid[1], network_to_s, metric)
|
133
|
+
end
|
134
|
+
|
135
|
+
def network_to_s
|
136
|
+
[network, network.mlen].join('/')
|
137
|
+
end
|
138
|
+
|
139
|
+
def method_missing(name, *args, &block)
|
140
|
+
if name.to_s =~ /^(local|remote)_address/
|
141
|
+
(__send__ "#{$1}_prefix").split('/')[0]
|
142
|
+
else
|
143
|
+
p name
|
144
|
+
raise
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
|
152
|
+
def _address_(host=1)
|
153
|
+
network + host
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
load "../../../test/ospfv2/ls_db/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
data/lib/lsa/external.rb
ADDED
@@ -0,0 +1,347 @@
|
|
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
|
+
=begin rdoc
|
24
|
+
|
25
|
+
A.4.5 AS-external-LSAs
|
26
|
+
|
27
|
+
AS-external-LSAs are the Type 5 LSAs. These LSAs are originated by
|
28
|
+
AS boundary routers, and describe destinations external to the AS.
|
29
|
+
For details concerning the construction of AS-external-LSAs, see
|
30
|
+
Section 12.4.3.
|
31
|
+
|
32
|
+
AS-external-LSAs usually describe a particular external destination.
|
33
|
+
For these LSAs the Link State ID field specifies an IP network
|
34
|
+
number (if necessary, the Link State ID can also have one or more of
|
35
|
+
the network's "host" bits set; see Appendix E for details). AS-
|
36
|
+
external-LSAs are also used to describe a default route. Default
|
37
|
+
routes are used when no specific route exists to the destination.
|
38
|
+
When describing a default route, the Link State ID is always set to
|
39
|
+
DefaultDestination (0.0.0.0) and the Network Mask is set to 0.0.0.0.
|
40
|
+
|
41
|
+
|
42
|
+
0 1 2 3
|
43
|
+
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
|
44
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
45
|
+
| LS age | Options | 5 |
|
46
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
47
|
+
| Link State ID |
|
48
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
49
|
+
| Advertising Router |
|
50
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
51
|
+
| LS sequence number |
|
52
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
53
|
+
| LS checksum | length |
|
54
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
55
|
+
| Network Mask |
|
56
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
57
|
+
|E| 0 | metric |
|
58
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
59
|
+
| Forwarding address |
|
60
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
61
|
+
| External Route Tag |
|
62
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
63
|
+
|E| TOS | TOS metric |
|
64
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
65
|
+
| Forwarding address |
|
66
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
67
|
+
| External Route Tag |
|
68
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
69
|
+
| ... |
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
Network Mask
|
74
|
+
The IP address mask for the advertised destination. For
|
75
|
+
example, when advertising a class A network the mask 0xff000000
|
76
|
+
would be used.
|
77
|
+
|
78
|
+
bit E
|
79
|
+
The type of external metric. If bit E is set, the metric
|
80
|
+
specified is a Type 2 external metric. This means the metric is
|
81
|
+
considered larger than any link state path. If bit E is zero,
|
82
|
+
the specified metric is a Type 1 external metric. This means
|
83
|
+
that it is expressed in the same units as the link state metric
|
84
|
+
(i.e., the same units as interface cost).
|
85
|
+
|
86
|
+
metric
|
87
|
+
The cost of this route. Interpretation depends on the external
|
88
|
+
type indication (bit E above).
|
89
|
+
|
90
|
+
Forwarding address
|
91
|
+
Data traffic for the advertised destination will be forwarded to
|
92
|
+
this address. If the Forwarding address is set to 0.0.0.0, data
|
93
|
+
traffic will be forwarded instead to the LSA's originator (i.e.,
|
94
|
+
the responsible AS boundary router).
|
95
|
+
|
96
|
+
External Route Tag
|
97
|
+
A 32-bit field attached to each external route. This is not
|
98
|
+
used by the OSPF protocol itself. It may be used to communicate
|
99
|
+
information between AS boundary routers; the precise nature of
|
100
|
+
such information is outside the scope of this specification.
|
101
|
+
|
102
|
+
Additional TOS-specific information may also be included, for
|
103
|
+
backward compatibility with previous versions of the OSPF
|
104
|
+
specification ([Ref9]). For each desired TOS, TOS-specific
|
105
|
+
information is encoded as follows:
|
106
|
+
|
107
|
+
TOS The Type of Service that the following fields concern. The
|
108
|
+
encoding of TOS in OSPF LSAs is described in Section 12.3.
|
109
|
+
|
110
|
+
bit E
|
111
|
+
For backward-compatibility with [Ref9].
|
112
|
+
|
113
|
+
TOS metric
|
114
|
+
TOS-specific metric information.
|
115
|
+
|
116
|
+
Forwarding address
|
117
|
+
For backward-compatibility with [Ref9].
|
118
|
+
|
119
|
+
External Route Tag
|
120
|
+
For backward-compatibility with [Ref9].
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
(RFC 4915)
|
125
|
+
|
126
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
127
|
+
| Network Mask |
|
128
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
129
|
+
|E| 0 | metric |
|
130
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
131
|
+
| Forwarding address |
|
132
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
133
|
+
| External Route Tag |
|
134
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
135
|
+
|E| MT-ID | MT-ID metric |
|
136
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
137
|
+
| Forwarding address |
|
138
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
139
|
+
| External Route Tag |
|
140
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
141
|
+
| ... |
|
142
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
143
|
+
|
144
|
+
=end
|
145
|
+
|
146
|
+
|
147
|
+
require 'lsa/lsa'
|
148
|
+
|
149
|
+
require 'ie/metric'
|
150
|
+
require 'ie/mt_metric'
|
151
|
+
require 'ie/id'
|
152
|
+
require 'ie/external_route'
|
153
|
+
|
154
|
+
module OSPFv2
|
155
|
+
|
156
|
+
class External_Base < Lsa
|
157
|
+
|
158
|
+
Netmask = Class.new(OSPFv2::Id)
|
159
|
+
ExternalRoute = Class.new(OSPFv2::ExternalRoute)
|
160
|
+
|
161
|
+
|
162
|
+
attr_reader :netmask, :external_route, :mt_metrics
|
163
|
+
attr_writer_delegate :netmask, :external_route
|
164
|
+
|
165
|
+
def initialize(arg={})
|
166
|
+
@netmask, @external_route = nil
|
167
|
+
@mt_metrics=[]
|
168
|
+
super
|
169
|
+
end
|
170
|
+
|
171
|
+
def encode
|
172
|
+
@netmask ||= Netmask.new
|
173
|
+
external =[]
|
174
|
+
external << netmask.encode
|
175
|
+
external << external_route.encode
|
176
|
+
external << mt_metrics.collect { |x| x.encode } if mt_metrics
|
177
|
+
super external.join
|
178
|
+
end
|
179
|
+
|
180
|
+
def parse(s)
|
181
|
+
s = super(s)
|
182
|
+
netmask, external_route = s.slice!(0,16).unpack('Na*')
|
183
|
+
@netmask = Netmask.new netmask
|
184
|
+
@external_route = ExternalRoute.new external_route
|
185
|
+
while s.size>0
|
186
|
+
self << MtExternalRoute.new(s.slice!(0,12))
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def to_hash
|
191
|
+
super
|
192
|
+
end
|
193
|
+
|
194
|
+
def to_s_default
|
195
|
+
mt_metrics = self.mt_metrics.collect
|
196
|
+
super +
|
197
|
+
['',netmask, external_route, *mt_metrics ].collect { |x| x.to_s }.join("\n ")
|
198
|
+
end
|
199
|
+
|
200
|
+
def to_s_junos
|
201
|
+
super
|
202
|
+
end
|
203
|
+
|
204
|
+
# Extern 50.0.2.0 128.3.0.1 0x80000001 39 0x0 0x1454 48
|
205
|
+
# mask 255.255.255.0
|
206
|
+
# Topology default (ID 0)
|
207
|
+
# Type: 1, Metric: 0, Fwd addr: 0.0.0.0, Tag: 0.0.0.0
|
208
|
+
# Topology default (ID 0)
|
209
|
+
# Type: 1, Metric: 30, Fwd addr: 0.0.0.0, Tag: 0.0.0.10
|
210
|
+
def to_s_junos_verbose
|
211
|
+
mt_metrics = self.mt_metrics.collect
|
212
|
+
super +
|
213
|
+
['',netmask, external_route, *mt_metrics ].collect { |x| x.to_s }.join("\n ")
|
214
|
+
end
|
215
|
+
|
216
|
+
def mt_metrics=(val)
|
217
|
+
# p "in mt_metrics=(val)"
|
218
|
+
# p val
|
219
|
+
[val].flatten.each { |x| self << x }
|
220
|
+
end
|
221
|
+
|
222
|
+
def <<(ext_route)
|
223
|
+
@mt_metrics ||=[]
|
224
|
+
# p "calling MtExternalRoute with #{ext_route.inspect}"
|
225
|
+
route = MtExternalRoute.new(ext_route)
|
226
|
+
# p route
|
227
|
+
@mt_metrics << route
|
228
|
+
self
|
229
|
+
end
|
230
|
+
|
231
|
+
def forwarding_address=(val)
|
232
|
+
@external_route.forwarding_address=(val)
|
233
|
+
end
|
234
|
+
|
235
|
+
def type=(val)
|
236
|
+
@external_route.type=(val)
|
237
|
+
end
|
238
|
+
|
239
|
+
def tag=(val)
|
240
|
+
@external_route.tag=(val)
|
241
|
+
end
|
242
|
+
|
243
|
+
def metric=(val)
|
244
|
+
@external_route.metric=(val)
|
245
|
+
end
|
246
|
+
|
247
|
+
# FIXME: should be a mixin and extended Summary and External?
|
248
|
+
class << self
|
249
|
+
def count
|
250
|
+
@count ||= 0
|
251
|
+
end
|
252
|
+
|
253
|
+
def incr_count
|
254
|
+
self.count
|
255
|
+
@count += 1
|
256
|
+
end
|
257
|
+
|
258
|
+
def reset
|
259
|
+
@count = nil
|
260
|
+
end
|
261
|
+
|
262
|
+
def base_ip_addr(addr=EXTERNAL_BASE_ADDRESS)
|
263
|
+
@base_addr ||= IPAddr.new(addr)
|
264
|
+
end
|
265
|
+
|
266
|
+
def network
|
267
|
+
@base_addr + count
|
268
|
+
end
|
269
|
+
|
270
|
+
def new_lsdb(arg={})
|
271
|
+
new({:network=> base_ip_addr ^ incr_count}.merge(arg))
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
end
|
277
|
+
|
278
|
+
class AsExternal < External_Base
|
279
|
+
|
280
|
+
ExternalRoute = Class.new(OSPFv2::ExternalRoute)
|
281
|
+
|
282
|
+
class << self
|
283
|
+
def count
|
284
|
+
@count ||= 0
|
285
|
+
end
|
286
|
+
|
287
|
+
def incr_count
|
288
|
+
self.count
|
289
|
+
@count += 1
|
290
|
+
end
|
291
|
+
|
292
|
+
def reset
|
293
|
+
@count = nil
|
294
|
+
end
|
295
|
+
|
296
|
+
def base_ip_addr(addr=EXTERNAL_BASE_ADDRESS)
|
297
|
+
@base_addr ||= IPAddr.new(addr)
|
298
|
+
end
|
299
|
+
|
300
|
+
def network
|
301
|
+
@base_addr + count
|
302
|
+
end
|
303
|
+
|
304
|
+
def new_lsdb(arg={})
|
305
|
+
new({:network=> base_ip_addr ^ incr_count}.merge(arg))
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
def initialize(arg={})
|
311
|
+
if arg.is_a?(Hash)
|
312
|
+
arg = fix_hash(arg).merge!({:ls_type => :as_external_lsa,})
|
313
|
+
end
|
314
|
+
super
|
315
|
+
end
|
316
|
+
|
317
|
+
private
|
318
|
+
|
319
|
+
def fix_hash(arg)
|
320
|
+
# p 'HERE'
|
321
|
+
# p arg
|
322
|
+
if arg[:network]
|
323
|
+
addr = IPAddr.new arg[:network]
|
324
|
+
arg.delete :network
|
325
|
+
arg.store :netmask, addr.netmask
|
326
|
+
arg.store :ls_id, addr.to_s
|
327
|
+
end
|
328
|
+
route = arg[:external_route] ||={}
|
329
|
+
[:metric, :forwarding_address, :type, :tag].each do |e|
|
330
|
+
next unless arg[e]
|
331
|
+
route.store(e, arg[e]) if arg[e]
|
332
|
+
arg.delete(e)
|
333
|
+
end
|
334
|
+
arg.merge!(:external_route=>route)
|
335
|
+
# p "FIXED arg: #{arg.inspect}"
|
336
|
+
arg
|
337
|
+
end
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
def AsExternal.new_hash(h)
|
342
|
+
new(h)
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
load "../../../test/ospfv2/lsa/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|