bgp4r 0.0.3
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/COPYING +674 -0
- data/LICENSE.txt +53 -0
- data/README.rdoc +259 -0
- data/bgp/aggregator.rb +104 -0
- data/bgp/as_path.rb +223 -0
- data/bgp/atomic_aggregate.rb +42 -0
- data/bgp/attribute.rb +181 -0
- data/bgp/attributes.rb +34 -0
- data/bgp/cluster_list.rb +117 -0
- data/bgp/common.rb +204 -0
- data/bgp/communities.rb +139 -0
- data/bgp/extended_communities.rb +107 -0
- data/bgp/extended_community.rb +254 -0
- data/bgp/iana.rb +269 -0
- data/bgp/io.rb +116 -0
- data/bgp/label.rb +94 -0
- data/bgp/local_pref.rb +75 -0
- data/bgp/message.rb +894 -0
- data/bgp/mp_reach.rb +208 -0
- data/bgp/multi_exit_disc.rb +76 -0
- data/bgp/neighbor.rb +291 -0
- data/bgp/next_hop.rb +63 -0
- data/bgp/nlri.rb +303 -0
- data/bgp/orf.rb +88 -0
- data/bgp/origin.rb +88 -0
- data/bgp/originator_id.rb +73 -0
- data/bgp/path_attribute.rb +210 -0
- data/bgp/prefix_orf.rb +263 -0
- data/bgp/rd.rb +107 -0
- data/examples/bgp +65 -0
- data/examples/routegen +85 -0
- data/examples/routegen.yml +50 -0
- data/test/aggregator_test.rb +66 -0
- data/test/as_path_test.rb +149 -0
- data/test/atomic_aggregate_test.rb +35 -0
- data/test/attribute_test.rb +57 -0
- data/test/cluster_list_test.rb +39 -0
- data/test/common_test.rb +68 -0
- data/test/communities_test.rb +75 -0
- data/test/extended_communities_test.rb +111 -0
- data/test/extended_community_test.rb +93 -0
- data/test/label_test.rb +50 -0
- data/test/local_pref_test.rb +43 -0
- data/test/message_test.rb +294 -0
- data/test/mp_reach_test.rb +143 -0
- data/test/multi_exit_disc_test.rb +46 -0
- data/test/neighbor_test.rb +50 -0
- data/test/next_hop_test.rb +37 -0
- data/test/nlri_test.rb +189 -0
- data/test/origin_test.rb +57 -0
- data/test/originator_id_test.rb +38 -0
- data/test/path_attribute_test.rb +127 -0
- data/test/prefix_orf_test.rb +97 -0
- data/test/rd_test.rb +44 -0
- metadata +133 -0
data/bgp/mp_reach.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2008, 2009 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of BGP4R.
|
8
|
+
#
|
9
|
+
# BGP4R 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
|
+
# BGP4R 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 BGP4R. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'bgp/attribute'
|
25
|
+
require 'bgp/nlri'
|
26
|
+
|
27
|
+
module BGP
|
28
|
+
|
29
|
+
class Mp_unreach < Attr
|
30
|
+
|
31
|
+
attr_reader :safi, :nlris
|
32
|
+
|
33
|
+
def initialize(*args)
|
34
|
+
@safi, @nlris= 1, []
|
35
|
+
@flags, @type = OPTIONAL, MP_UNREACH
|
36
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
37
|
+
parse(args[0])
|
38
|
+
elsif args[0].is_a?(self.class)
|
39
|
+
parse(args[0].encode, *args[1..-1])
|
40
|
+
elsif args[0].is_a?(Hash) and args.size==1
|
41
|
+
set(*args)
|
42
|
+
else
|
43
|
+
raise ArgumentError, "invalid argument"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def afi
|
48
|
+
@afi ||= @nlris[0].afi
|
49
|
+
end
|
50
|
+
|
51
|
+
def set(h)
|
52
|
+
@safi = h[:safi]
|
53
|
+
case @safi
|
54
|
+
when 1,2
|
55
|
+
@nlris = [h[:prefix]].flatten.collect { |p| p.is_a?(Prefix) ? p : Prefix.new(p) }
|
56
|
+
when 4
|
57
|
+
@nlris = [h[:nlri]].flatten.collect { |n|
|
58
|
+
prefix = n[:prefix].is_a?(String) ? Prefix.new(n[:prefix]) : n[:prefix]
|
59
|
+
Labeled.new(prefix, *n[:label])
|
60
|
+
}
|
61
|
+
when 128,129 ; @nlris = [h[:nlri]].flatten.collect { |n|
|
62
|
+
prefix = n[:prefix].is_a?(Prefix) ? n[:prefix] : Prefix.new(n[:prefix])
|
63
|
+
rd = n[:rd].is_a?(Rd) ? n[:rd] : Rd.new(*n[:rd])
|
64
|
+
Labeled.new(Vpn.new(prefix,rd), *n[:label]) }
|
65
|
+
else
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def mp_unreach
|
70
|
+
"\n AFI #{IANA.afi(afi)} (#{afi}), SAFI #{IANA.safi(safi)} (#{safi})" +
|
71
|
+
(['']+ @nlris.collect { |nlri| nlri.to_s }).join("\n ")
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s(method=:default)
|
75
|
+
super(mp_unreach, method)
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse(s)
|
79
|
+
@flags, @type, len, value = super(s)
|
80
|
+
@afi, @safi = value.slice!(0,3).unpack('nC')
|
81
|
+
while value.size>0
|
82
|
+
blen = value.slice(0,1).unpack('C')[0]
|
83
|
+
@nlris << Nlri.factory(value.slice!(0,(blen+7)/8+1), @afi, @safi)
|
84
|
+
end
|
85
|
+
raise RuntimeError, "leftover afer parsing: #{value.unpack('H*')}" if value.size>0
|
86
|
+
end
|
87
|
+
|
88
|
+
def encode
|
89
|
+
super([afi, @safi, @nlris.collect { |n| n.encode }.join].pack('nCa*'))
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
class Mp_reach < Attr
|
95
|
+
|
96
|
+
attr_reader :safi, :nlris
|
97
|
+
|
98
|
+
def initialize(*args)
|
99
|
+
@safi, @nexthops, @nlris= 1, [], [] # default is ipv4/unicast
|
100
|
+
@flags, @type = OPTIONAL, MP_REACH
|
101
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
102
|
+
parse(args[0])
|
103
|
+
elsif args[0].is_a?(self.class)
|
104
|
+
parse(args[0].encode, *args[1..-1])
|
105
|
+
elsif args[0].is_a?(Hash) and args.size==1
|
106
|
+
set(*args)
|
107
|
+
else
|
108
|
+
raise ArgumentError, "invalid argument"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def afi
|
113
|
+
@afi ||= @nexthops[0].afi
|
114
|
+
end
|
115
|
+
|
116
|
+
def set(h)
|
117
|
+
@safi = h[:safi]
|
118
|
+
case @safi
|
119
|
+
when 1,2,4 ; @nexthops = [h[:nexthop]].flatten.collect { |nh| Prefix.new(nh) }
|
120
|
+
when 128,129 ; @nexthops = [h[:nexthop]].flatten.collect { |nh| Vpn.new(nh) }
|
121
|
+
else
|
122
|
+
end
|
123
|
+
case @safi
|
124
|
+
when 1,2
|
125
|
+
@nlris = [h[:prefix]].flatten.collect { |n| Prefix.new(n) }
|
126
|
+
when 4
|
127
|
+
@nlris = [h[:nlri]].flatten.collect { |n|
|
128
|
+
prefix = n[:prefix].is_a?(String) ? Prefix.new(n[:prefix]) : n[:prefix]
|
129
|
+
Labeled.new(prefix, *n[:label])
|
130
|
+
}
|
131
|
+
when 128,129 ; @nlris = [h[:nlri]].flatten.collect { |n|
|
132
|
+
prefix = n[:prefix].is_a?(Prefix) ? n[:prefix] : Prefix.new(n[:prefix])
|
133
|
+
rd = n[:rd].is_a?(Rd) ? n[:rd] : Rd.new(*n[:rd])
|
134
|
+
Labeled.new(Vpn.new(prefix,rd), *n[:label]) }
|
135
|
+
else
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def nexthops
|
140
|
+
@nexthops.collect { |nh| nh.nexthop }.join(", ")
|
141
|
+
end
|
142
|
+
|
143
|
+
def mp_reach
|
144
|
+
"\n AFI #{IANA.afi(afi)} (#{afi}), SAFI #{IANA.safi(safi)} (#{safi})" +
|
145
|
+
"\n nexthop: " + nexthops +
|
146
|
+
(['']+ @nlris.collect { |nlri| nlri.to_s }).join("\n ")
|
147
|
+
end
|
148
|
+
|
149
|
+
def to_s(method=:default)
|
150
|
+
super(mp_reach, method)
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_hash
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
def parse(s)
|
158
|
+
@flags, @type, len, value = super(s)
|
159
|
+
@afi, @safi, nh_len = value.slice!(0,4).unpack('nCC')
|
160
|
+
parse_next_hops value.slice!(0,nh_len).is_packed
|
161
|
+
value.slice!(0,1)
|
162
|
+
while value.size>0
|
163
|
+
blen = value.slice(0,1).unpack('C')[0]
|
164
|
+
@nlris << Nlri.factory(value.slice!(0,(blen+7)/8+1), @afi, @safi)
|
165
|
+
end
|
166
|
+
raise RuntimeError, "leftover afer parsing: #{value.unpack('H*')}" if value.size>0
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
def parse_next_hops(s)
|
171
|
+
while s.size>0
|
172
|
+
case @safi
|
173
|
+
when 1,2,4
|
174
|
+
case @afi
|
175
|
+
when 1
|
176
|
+
@nexthops << Prefix.new([32,s.slice!(0,4)].pack('Ca*'),1)
|
177
|
+
when 2
|
178
|
+
@nexthops << Prefix.new([128,s.slice!(0,16)].pack('Ca*'),2)
|
179
|
+
end
|
180
|
+
when 128,129
|
181
|
+
@nexthops << Vpn.new([64+32,s.slice!(0,12)].pack('Ca*'))
|
182
|
+
else
|
183
|
+
raise RuntimeError, "cannot parse nexthop for safi #{@safi}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def encode(what=:mp_reach)
|
189
|
+
case what
|
190
|
+
when :mp_reach
|
191
|
+
nexthops = @nexthops.collect { |nh| nh.encode(false) }.join
|
192
|
+
super([afi, @safi, nexthops.size, nexthops, 0, @nlris.collect { |n| n.encode }.join].pack('nCCa*Ca*'))
|
193
|
+
when :mp_unreach
|
194
|
+
super([afi, @safi, @nlris.collect { |n| n.encode }.join].pack('nCa*'))
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def new_unreach
|
199
|
+
s = encode(:mp_unreach)
|
200
|
+
s[1]= [MP_UNREACH].pack('C')
|
201
|
+
Mp_unreach.new(s)
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2008, 2009 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of BGP4R.
|
8
|
+
#
|
9
|
+
# BGP4R 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
|
+
# BGP4R 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 BGP4R. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'bgp/attribute'
|
25
|
+
|
26
|
+
module BGP
|
27
|
+
|
28
|
+
class Multi_exit_disc < Attr
|
29
|
+
|
30
|
+
def initialize(arg=0)
|
31
|
+
@flags, @type=OPTIONAL, MULTI_EXIT_DISC
|
32
|
+
if arg.is_a?(String) and arg.is_packed?
|
33
|
+
parse(arg)
|
34
|
+
elsif arg.is_a?(self.class)
|
35
|
+
parse(arg.encode)
|
36
|
+
elsif arg.is_a?(Integer)
|
37
|
+
@med = arg
|
38
|
+
elsif arg.is_a?(Hash) and arg[:multi_exit_disc] or arg[:med]
|
39
|
+
self.med = arg[:med] if arg[:med]
|
40
|
+
self.med = arg[:multi_exit_disc] if arg[:multi_exit_disc]
|
41
|
+
else
|
42
|
+
raise ArgumentError, "invalid argument, #{arg.inspect}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def med=(val)
|
47
|
+
raise ArgumentError, "invalid argument" unless val.is_a?(Integer)
|
48
|
+
@med=val
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_i
|
52
|
+
@med
|
53
|
+
end
|
54
|
+
|
55
|
+
def encode
|
56
|
+
super([to_i].pack('N'))
|
57
|
+
end
|
58
|
+
|
59
|
+
def multi_exit_disc
|
60
|
+
format("(0x%4.4x) %d", to_i, to_i)
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s(method=:default)
|
64
|
+
super(multi_exit_disc, method)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def parse(s)
|
70
|
+
@flags, @type, len, @med=super(s,'N')
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
data/bgp/neighbor.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2008, 2009 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of BGP4R.
|
8
|
+
#
|
9
|
+
# BGP4R 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
|
+
# BGP4R 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 BGP4R. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
require 'socket'
|
24
|
+
require 'thread'
|
25
|
+
require 'observer'
|
26
|
+
|
27
|
+
module BGP
|
28
|
+
|
29
|
+
class Neighbor
|
30
|
+
include Observable
|
31
|
+
|
32
|
+
def initialize(*args)
|
33
|
+
@opt_parms = []
|
34
|
+
if args.size==1 and args[0].is_a?(Hash)
|
35
|
+
@version = args[0][:version] if args[0][:version]
|
36
|
+
@my_as = args[0][:my_as] if args[0][:my_as]
|
37
|
+
@holdtime = args[0][:holdtime] if args[0][:holdtime]
|
38
|
+
@id = args[0][:id] if args[0][:id]
|
39
|
+
@remote_addr = args[0][:remote_addr] if args[0][:remote_addr]
|
40
|
+
@local_addr = args[0][:local_addr] if args[0][:local_addr]
|
41
|
+
else
|
42
|
+
@version, @my_as, @holdtime, @id, @remote_addr, @local_addr = args
|
43
|
+
end
|
44
|
+
@as4byte=false
|
45
|
+
@state = :Idle
|
46
|
+
@threads=ThreadGroup.new
|
47
|
+
@mutex = Mutex.new
|
48
|
+
@eventQ = Queue.new
|
49
|
+
event_dispatch
|
50
|
+
end
|
51
|
+
|
52
|
+
# neighbor.capability :as4_byte
|
53
|
+
# neighbor.capability :route_refresh
|
54
|
+
# neighbor.capability :route_refresh, 128
|
55
|
+
# neighbor.capability :mbgp, :ipv4, :unicast
|
56
|
+
# neighbor.capability :mbgp, :ipv4, :multicast
|
57
|
+
def capability(*args)
|
58
|
+
@opt_parms << if args[0].is_a?(Symbol)
|
59
|
+
case args[0]
|
60
|
+
when :route_refresh ; Route_refresh_cap.new(*args[1..-1])
|
61
|
+
when :mbgp ; Mbgp_cap.new(*args[1..-1])
|
62
|
+
when :as4_byte ; As4_cap.new(@my_as)
|
63
|
+
end
|
64
|
+
elsif args[0].is_a?(Capability) and args.size==1
|
65
|
+
args[0]
|
66
|
+
else
|
67
|
+
raise ArgumentError, "Invalid argument"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def state
|
72
|
+
@state.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def retry_thread(action=:start)
|
76
|
+
case action
|
77
|
+
when :start
|
78
|
+
@restart_thread = Thread.new do
|
79
|
+
Thread.current['name']='restart'
|
80
|
+
loop do
|
81
|
+
enable if @state == :Idle
|
82
|
+
sleep(5)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
when :stop
|
87
|
+
if defined? @restart_thread and @restart_thread.alive?
|
88
|
+
@restart_thread.kill ; @restart_thread.join
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def event_dispatch
|
94
|
+
Thread.new(@eventQ) do |eventQ|
|
95
|
+
loop do
|
96
|
+
ev, type, m = eventQ.deq
|
97
|
+
case ev
|
98
|
+
when :ev_msg
|
99
|
+
msg = BGP::Message.factory(m)
|
100
|
+
Log.info "Recv#{msg.class.to_s.split('::')[-1]}"
|
101
|
+
Log.debug "Recv #{msg}\n"
|
102
|
+
changed and notify_observers(msg)
|
103
|
+
if msg.is_a?(Update)
|
104
|
+
rcv_update(msg)
|
105
|
+
elsif msg.is_a?(Notification)
|
106
|
+
rcv_notification(msg)
|
107
|
+
elsif msg.is_a?(Open)
|
108
|
+
rcv_open(msg)
|
109
|
+
elsif msg.is_a?(Route_refresh)
|
110
|
+
rcv_route_refresh(msg)
|
111
|
+
elsif msg.is_a?(Orf_route_refresh)
|
112
|
+
rcv_route_refresh(msg)
|
113
|
+
elsif msg.is_a?(Keepalive)
|
114
|
+
rcv_keepalive
|
115
|
+
else
|
116
|
+
Log.error "unexpected message type #{type}"
|
117
|
+
end
|
118
|
+
when :ev_conn_reset
|
119
|
+
Log.warn "#{type}"
|
120
|
+
disable
|
121
|
+
when :ev_holdtime_expire
|
122
|
+
Log.warn "Holdtime expire: #{type}"
|
123
|
+
disable
|
124
|
+
else
|
125
|
+
Log.error "unexpected event #{ev}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def clean
|
132
|
+
@threads.list.each { |x|
|
133
|
+
x.exit; x.join
|
134
|
+
Log.info "#{x['name']}: stopped at #{Time.now.strftime("%I:%M:%S%P")}"
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def _open_msg_
|
140
|
+
@open = BGP::Open.new(@version, @my_as, @holdtime, @id, *@opt_parms)
|
141
|
+
end
|
142
|
+
private :_open_msg_
|
143
|
+
|
144
|
+
def enable(auto_retry=:no_auto_retry, wait= :wait)
|
145
|
+
return if @state == :Established
|
146
|
+
disable unless @state == :Idle
|
147
|
+
|
148
|
+
init_socket
|
149
|
+
init_io
|
150
|
+
@open = _open_msg_
|
151
|
+
|
152
|
+
[@in, @out].each { |io|
|
153
|
+
io.start
|
154
|
+
@threads.add io.thread
|
155
|
+
}
|
156
|
+
|
157
|
+
def in ; @in.thread ; end
|
158
|
+
def out ; @out.thread ; end
|
159
|
+
|
160
|
+
send_open :ev_send_open
|
161
|
+
|
162
|
+
retry_thread if auto_retry == :auto_retry
|
163
|
+
|
164
|
+
if wait == :wait
|
165
|
+
loop do
|
166
|
+
sleep(0.3)
|
167
|
+
break if @state == :Established
|
168
|
+
end
|
169
|
+
Log.info "#{self} started"
|
170
|
+
end
|
171
|
+
|
172
|
+
rescue => e
|
173
|
+
Log.error "#{e}"
|
174
|
+
disable
|
175
|
+
end
|
176
|
+
alias start enable
|
177
|
+
|
178
|
+
def disable
|
179
|
+
@socket.close if defined?(@socket) and not @socket.closed?
|
180
|
+
clean
|
181
|
+
new_state :Idle, "Disable"
|
182
|
+
end
|
183
|
+
alias stop disable
|
184
|
+
|
185
|
+
def send_message(m)
|
186
|
+
return unless @out
|
187
|
+
unless m.is_a?(String)
|
188
|
+
Log.info "Send#{m.class.to_s.split('::')[-1]}"
|
189
|
+
Log.debug "Send #{m.is_a?(Update) ? m.to_s(@as4byte) : m }\n"
|
190
|
+
end
|
191
|
+
if m.is_a?(Update)
|
192
|
+
@out.enq m.encode(@as4byte)
|
193
|
+
else
|
194
|
+
@out.enq m
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def init_socket
|
199
|
+
@socket = Socket.new(Socket::PF_INET, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)
|
200
|
+
remote = Socket.pack_sockaddr_in(179, @remote_addr)
|
201
|
+
local = Socket.pack_sockaddr_in(0, @local_addr) unless @local_addr.nil?
|
202
|
+
remote_sock_addr = Socket.pack_sockaddr_in(179, @remote_addr)
|
203
|
+
local_sock_addr = Socket.pack_sockaddr_in(0, @local_addr) unless @local_addr.nil?
|
204
|
+
@socket.bind(local_sock_addr) unless @local_addr.nil?
|
205
|
+
@socket.connect(remote_sock_addr)
|
206
|
+
end
|
207
|
+
|
208
|
+
def init_io
|
209
|
+
@in = BGP::IO::Input.new(@socket, @holdtime, self)
|
210
|
+
@out = BGP::IO::Output.new(@socket, @holdtime, self)
|
211
|
+
new_state(:Active, "Open Socket")
|
212
|
+
end
|
213
|
+
|
214
|
+
def update(*args)
|
215
|
+
@eventQ.enq(args)
|
216
|
+
end
|
217
|
+
|
218
|
+
def new_state(state, txt='')
|
219
|
+
Log.info "#{txt} old state #{@state} new state #{state}"
|
220
|
+
@state = state
|
221
|
+
end
|
222
|
+
|
223
|
+
def _send_open_(open)
|
224
|
+
send_message open
|
225
|
+
end
|
226
|
+
private :_send_open_
|
227
|
+
|
228
|
+
def send_open(ev)
|
229
|
+
case @state
|
230
|
+
when :OpenRecv
|
231
|
+
_send_open_ @open ; new_state :OpenConfirm, ev
|
232
|
+
when :Active
|
233
|
+
_send_open_ @open ; new_state :OpenSent, ev
|
234
|
+
else
|
235
|
+
Log.warn "#{self.class}: attempt to send OPEN msg while in #{@state}"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def rcv_open(o)
|
240
|
+
@rmt_version = o.version
|
241
|
+
@rmt_as = o.local_as
|
242
|
+
@rmt_bgp_id = o.bgp_id
|
243
|
+
|
244
|
+
if @holdtime > o.holdtime
|
245
|
+
@out.holdtime = @in.holdtime = o.holdtime
|
246
|
+
end
|
247
|
+
|
248
|
+
case @state
|
249
|
+
when :OpenSent
|
250
|
+
send_message(BGP::Message.keepalive)
|
251
|
+
new_state :OpenConfirm, "RecvOpen"
|
252
|
+
when :Active
|
253
|
+
send_open "RecvOpen"
|
254
|
+
new_state :OpenConfirm, "RecvOpen"
|
255
|
+
else
|
256
|
+
Log.warn "#{self.class}: received open message while in state #{@state}"
|
257
|
+
end
|
258
|
+
|
259
|
+
@as4byte = (@open.has?(As4_cap) and o.has?(As4_cap))
|
260
|
+
end
|
261
|
+
|
262
|
+
def rcv_keepalive
|
263
|
+
if @state == :OpenConfirm
|
264
|
+
send_message(BGP::Keepalive.new)
|
265
|
+
Log.debug "SendKeepAlive"
|
266
|
+
new_state(:Established, 'RecvKeepAlive')
|
267
|
+
@keepalive_thread = Thread.new(@holdtime/3) do |h|
|
268
|
+
Thread.current['name'] = "BGP Keepalive interval:(#{h})"
|
269
|
+
loop do
|
270
|
+
sleep(h)
|
271
|
+
send_message(BGP::Keepalive.new)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
@threads.add(@keepalive_thread)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def rcv_notification(m)
|
279
|
+
Log.info "#{m}"
|
280
|
+
disable
|
281
|
+
end
|
282
|
+
|
283
|
+
def to_s
|
284
|
+
"version: #{@version}, id: #{@id}, as: #{@my_as}, holdtime: #{@holdtime}, peer addr: #{@remote_addr}, local addr: #{@local_addr}"
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
291
|
+
load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
data/bgp/next_hop.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2008, 2009 Jean-Michel Esnault.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# This file is part of BGP4R.
|
8
|
+
#
|
9
|
+
# BGP4R 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
|
+
# BGP4R 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 BGP4R. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'bgp/attribute'
|
25
|
+
|
26
|
+
module BGP
|
27
|
+
|
28
|
+
class Next_hop < Attr
|
29
|
+
|
30
|
+
def initialize(*args)
|
31
|
+
@flags, @type = WELL_KNOWN_MANDATORY, NEXT_HOP
|
32
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
33
|
+
parse(args[0])
|
34
|
+
elsif args[0].is_a?(self.class)
|
35
|
+
parse(args[0].encode, *args[1..-1])
|
36
|
+
else
|
37
|
+
@next_hop = IPAddr.create(*args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def next_hop
|
42
|
+
@next_hop.to_s
|
43
|
+
end
|
44
|
+
def to_s(method=:default)
|
45
|
+
super(next_hop, method)
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_i
|
49
|
+
@next_hop.to_i
|
50
|
+
end
|
51
|
+
def parse(s)
|
52
|
+
@flags, @type, len, value = super(s)
|
53
|
+
@next_hop = IPAddr.new_ntoh(value[0,4])
|
54
|
+
end
|
55
|
+
|
56
|
+
def encode
|
57
|
+
super(@next_hop.encode)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|