bgp4r 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/COPYING +674 -0
  2. data/LICENSE.txt +53 -0
  3. data/README.rdoc +259 -0
  4. data/bgp/aggregator.rb +104 -0
  5. data/bgp/as_path.rb +223 -0
  6. data/bgp/atomic_aggregate.rb +42 -0
  7. data/bgp/attribute.rb +181 -0
  8. data/bgp/attributes.rb +34 -0
  9. data/bgp/cluster_list.rb +117 -0
  10. data/bgp/common.rb +204 -0
  11. data/bgp/communities.rb +139 -0
  12. data/bgp/extended_communities.rb +107 -0
  13. data/bgp/extended_community.rb +254 -0
  14. data/bgp/iana.rb +269 -0
  15. data/bgp/io.rb +116 -0
  16. data/bgp/label.rb +94 -0
  17. data/bgp/local_pref.rb +75 -0
  18. data/bgp/message.rb +894 -0
  19. data/bgp/mp_reach.rb +208 -0
  20. data/bgp/multi_exit_disc.rb +76 -0
  21. data/bgp/neighbor.rb +291 -0
  22. data/bgp/next_hop.rb +63 -0
  23. data/bgp/nlri.rb +303 -0
  24. data/bgp/orf.rb +88 -0
  25. data/bgp/origin.rb +88 -0
  26. data/bgp/originator_id.rb +73 -0
  27. data/bgp/path_attribute.rb +210 -0
  28. data/bgp/prefix_orf.rb +263 -0
  29. data/bgp/rd.rb +107 -0
  30. data/examples/bgp +65 -0
  31. data/examples/routegen +85 -0
  32. data/examples/routegen.yml +50 -0
  33. data/test/aggregator_test.rb +66 -0
  34. data/test/as_path_test.rb +149 -0
  35. data/test/atomic_aggregate_test.rb +35 -0
  36. data/test/attribute_test.rb +57 -0
  37. data/test/cluster_list_test.rb +39 -0
  38. data/test/common_test.rb +68 -0
  39. data/test/communities_test.rb +75 -0
  40. data/test/extended_communities_test.rb +111 -0
  41. data/test/extended_community_test.rb +93 -0
  42. data/test/label_test.rb +50 -0
  43. data/test/local_pref_test.rb +43 -0
  44. data/test/message_test.rb +294 -0
  45. data/test/mp_reach_test.rb +143 -0
  46. data/test/multi_exit_disc_test.rb +46 -0
  47. data/test/neighbor_test.rb +50 -0
  48. data/test/next_hop_test.rb +37 -0
  49. data/test/nlri_test.rb +189 -0
  50. data/test/origin_test.rb +57 -0
  51. data/test/originator_id_test.rb +38 -0
  52. data/test/path_attribute_test.rb +127 -0
  53. data/test/prefix_orf_test.rb +97 -0
  54. data/test/rd_test.rb +44 -0
  55. 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