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