bgp4r 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|