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
@@ -0,0 +1,210 @@
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/attributes'
25
+
26
+ module BGP
27
+
28
+ class Path_attribute
29
+ include BGP::ATTR
30
+ def initialize(*args)
31
+ if args.size <= 2 and args[0].is_a?(String) and args[0].is_packed?
32
+ s = args[0]
33
+ @attributes=[]
34
+ while s.size>0
35
+ @attributes << Attr.factory(s)
36
+ end
37
+ else
38
+ add(*args)
39
+ end
40
+ end
41
+ def add(*args)
42
+ @attributes ||=[]
43
+ args.each { |arg| @attributes << arg if arg.is_a?(BGP::Attr) }
44
+ self
45
+ end
46
+ alias << add
47
+
48
+ def to_ary
49
+ @attributes
50
+ end
51
+
52
+ def to_s(method=:default,as4byte=false)
53
+ "Path Attributes:" + ([""] + @attributes.collect { |a|
54
+ if as4byte and a.is_a?(As_path)
55
+ a.to_s(method, as4byte)
56
+ else
57
+ a.to_s(method)
58
+ end
59
+ }).join("\n ")
60
+ end
61
+
62
+ def find(klass)
63
+ @attributes.find { |a| a.is_a?(klass) }
64
+ end
65
+
66
+ def size
67
+ @attributes.size
68
+ end
69
+
70
+ def [](type)
71
+ case type
72
+ when ORIGIN, :origin
73
+ find(Origin)
74
+ when AS_PATH, :as_path
75
+ find(As_path)
76
+ when NEXT_HOP, :next_hop
77
+ find(Next_hop)
78
+ when MULTI_EXIT_DISC, :multi_exit_disc
79
+ find(Multi_exit_disc)
80
+ when LOCAL_PREF, :local_pref
81
+ find(Local_pref)
82
+ when ATOMIC_AGGREGATE, :atomic_aggregate
83
+ find(Atomic_aggregate)
84
+ when AGGREGATOR, :aggregator
85
+ find(Aggregator)
86
+ when COMMUNITIES, :communities
87
+ find(Communities)
88
+ when ORIGINATOR_ID, :originator_id
89
+ find(Originator_id)
90
+ when CLUSTER_LIST, :cluster_list
91
+ find(Cluster_list)
92
+ when MP_REACH, :mp_reach
93
+ find(Mp_reach)
94
+ when MP_UNREACH, :mp_unreach
95
+ find(Mp_unreach)
96
+ when EXTENDED_COMMUNITY, :extended_community
97
+ find(Extended_communities)
98
+ when AS4_PATH, :as4_path
99
+ find(As4_path)
100
+ when AS4_AGGREGATOR, :as4_aggregator
101
+ find(As4_aggregator)
102
+ end
103
+ end
104
+
105
+ def has?(klass=nil)
106
+ if klass
107
+ @attributes.find { |a| a.is_a?(klass) }.nil? ? false : true
108
+ else
109
+ @attributes.collect { |attr| attr.class }
110
+ end
111
+ end
112
+
113
+ def encode(as4byte=false)
114
+ [@attributes.compact.collect { |x| as4byte ? x.encode4 : x.encode }.join].pack('a*')
115
+ end
116
+
117
+ def insert(*args)
118
+ for arg in args
119
+ next unless arg.is_a?(Attr)
120
+ to_ary.insert(0,arg)
121
+ end
122
+ self
123
+ end
124
+
125
+ def append(*args)
126
+ for arg in args
127
+ next unless arg.is_a?(Attr)
128
+ to_ary << (arg)
129
+ end
130
+ self
131
+ end
132
+
133
+ def replace(*args)
134
+ for arg in args
135
+ next unless arg.is_a?(Attr)
136
+ attr = to_ary.find { |x| x.class == arg.class }
137
+ if attr.nil?
138
+ append(arg)
139
+ else
140
+ index = to_ary.index(attr)
141
+ to_ary[index] = arg
142
+ end
143
+ end
144
+ self
145
+ end
146
+
147
+ def delete(*klasses)
148
+ for klass in klasses
149
+ next unless klass.is_a?(Class)
150
+ to_ary.delete_if { |x| x.class == klass }
151
+ end
152
+ self
153
+ end
154
+
155
+ end
156
+
157
+ end
158
+
159
+ module BGP
160
+
161
+ class Attr
162
+ include BGP::ATTR
163
+ def self.factory(s)
164
+ flags, type = s.unpack('CC')
165
+ case type
166
+ when ORIGIN
167
+ Origin.new(s)
168
+ when AS_PATH
169
+ As_path.new(s)
170
+ when NEXT_HOP
171
+ Next_hop.new(s)
172
+ when MULTI_EXIT_DISC
173
+ Multi_exit_disc.new(s)
174
+ when LOCAL_PREF
175
+ Local_pref.new(s)
176
+ when ATOMIC_AGGREGATE
177
+ Atomic_aggregate.new(s)
178
+ when AGGREGATOR
179
+ Aggregator.new(s)
180
+ when COMMUNITIES
181
+ Communities.new(s)
182
+ when ATOMIC_AGGREGATE
183
+ Atomic_aggregate.new(s)
184
+ when ORIGINATOR_ID
185
+ Originator_id.new(s)
186
+ when CLUSTER_LIST
187
+ Cluster_list.new(s)
188
+ when MP_REACH
189
+ Mp_reach.new(s)
190
+ when MP_UNREACH
191
+ Mp_unreach.new(s)
192
+ when EXTENDED_COMMUNITY
193
+ Extended_communities.new(s)
194
+ else
195
+ if flags & 0x10==1
196
+ len = s.slice!(0,2).unpack("n")[0]
197
+ else
198
+ len = s.slice!(0,1).unpack('C')[0]
199
+ end
200
+ s.slice!(0,len)
201
+ raise RuntimeError, "factory for #{type} to be implemented soon"
202
+ nil
203
+ end
204
+ end
205
+
206
+ end
207
+
208
+ end
209
+
210
+ load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
data/bgp/prefix_orf.rb ADDED
@@ -0,0 +1,263 @@
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/nlri'
25
+ require 'bgp/orf'
26
+
27
+ module BGP
28
+
29
+ class Prefix_entry < Orf::Entry
30
+
31
+ @_seqn_ = -10
32
+ class << self
33
+ attr_accessor :_seqn_
34
+ def seqn ; Address_prefix_orf_entry._seqn_ +=10 ;end
35
+ end
36
+
37
+ def initialize(*args)
38
+ if args[0].is_a?(String) and args[0].is_packed?
39
+ _parse_(*args)
40
+ elsif args.size==6
41
+ @action, @match, @seqn, @min, @max, prefix = args
42
+ @prefix = BGP::Prefix.new(prefix)
43
+ elsif args.size==4
44
+ @min, @max = 0, 0
45
+ @action, @match, @seqn, prefix = args
46
+ @prefix = BGP::Prefix.new(prefix)
47
+ elsif args.size==1 and args[0].is_a?(Hash)
48
+ set(args[0])
49
+ else
50
+ p args
51
+ raise
52
+ end
53
+ end
54
+
55
+ def action=(val)
56
+ case val
57
+ when 0, :add
58
+ @action=0
59
+ when 1, :remove
60
+ @action=1
61
+ when 2, :remove_all
62
+ @action=2
63
+ end
64
+ end
65
+
66
+ def action_to_i
67
+ @action
68
+ end
69
+
70
+ def action_to_s
71
+ case @action
72
+ when 0 ; 'add'
73
+ when 1 ; 'remove'
74
+ when 2 ; 'remove all'
75
+ else
76
+ 'unknown action'
77
+ end
78
+ end
79
+
80
+ def match_to_i
81
+ @match
82
+ end
83
+
84
+ def match_to_s
85
+ case @match
86
+ when 0 ; 'permit'
87
+ when 1 ; 'deny'
88
+ end
89
+ end
90
+
91
+ def match=(val)
92
+ case val
93
+ when 0, :permit ; @match=0
94
+ when 1, :deny ; @match=1
95
+ else
96
+ raise
97
+ end
98
+ end
99
+
100
+ def set(h)
101
+ self.action = h[:action] ||= 0
102
+ self.match = h[:match] ||= 0
103
+ @seqn = h[:seqn] ||= 0
104
+ @min = h[:min] ||= 0
105
+ @max = h[:max] ||= 0
106
+ @prefix = BGP::Prefix.new(h[:prefix]) if h[:prefix]
107
+ end
108
+
109
+ def encode
110
+ [_first_octet_,@seqn, @min, @max, @prefix.encode(true)].pack('CNCCa*')
111
+ end
112
+
113
+ def to_s
114
+ #FIXME unit-test
115
+ s = format("seq %3s %6s %s", @seqn, action_to_s, @prefix)
116
+ s += " ge #{@min}" if @min>0
117
+ s += " le #{@max}" if @max>0
118
+ s += " #{match_to_s}"
119
+ s
120
+ end
121
+
122
+ private
123
+
124
+ def _first_octet_
125
+ (@action<<6) | ((@match & 0x1) << 5)
126
+ end
127
+
128
+ def size
129
+ @prefix.nbyte+7+1
130
+ end
131
+
132
+ def _parse_(s, afi=1)
133
+ #puts "s before parse: #{s.unpack('H*')}"
134
+ o1, @seqn, @min, @max, prefix = s.unpack('CNCCa*')
135
+ @action = o1 >> 6
136
+ @match = (o1 >> 5) & 1
137
+ @prefix = BGP::Prefix.new(prefix.is_packed, afi)
138
+ #puts "size of orf entry is : #{size}"
139
+ s.slice!(0,size)
140
+ #puts "s after parse: #{s.unpack('H*')}"
141
+ end
142
+
143
+ def self.add(*args) ; Prefix_entry.new(0,*args) ; end
144
+ def self.add_and_deny(*args) ; Prefix_entry.new(0,1,*args) ; end
145
+ def self.add_and_permit(*args) ; Prefix_entry.new(0,0,*args) ; end
146
+ def self.remove(*args) ; Prefix_entry.new(1,*args) ; end
147
+ def self.remove_and_deny(*args) ; Prefix_entry.new(1,1,*args) ; end
148
+ def self.remove_and_permit(*args) ; Prefix_entry.new(1,0,*args) ; end
149
+ def self.remove_all(*args) ; Prefix_entry.new(2,0) ; end
150
+
151
+ end
152
+
153
+ end
154
+
155
+ class BGP::Prefix_orf < BGP::Orf
156
+
157
+ def initialize(*args)
158
+ if args[0].is_a?(String) and args[0].is_packed?
159
+ _parse_(*args)
160
+ elsif args[0].is_a?(self.class) and args[0].respond_to?(:encode)
161
+ _parse_(args[0].encode)
162
+ else
163
+ super(64, *args)
164
+ end
165
+ end
166
+
167
+ def add(e)
168
+ raise ArgumentError, "invalid argument" unless e.is_a?(BGP::Prefix_entry)
169
+ super(e)
170
+ end
171
+
172
+ def _parse_(s)
173
+ @entries=[]
174
+ @type, len, entries = s.unpack('Cna*')
175
+ while entries.size>0
176
+ #p entries.unpack('H*')
177
+ @entries << BGP::Prefix_entry.new(entries.is_packed)
178
+ end
179
+ end
180
+
181
+ def cisco_prefix_entry_type
182
+ @type=130
183
+ end
184
+
185
+ end
186
+
187
+ load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
188
+
189
+ __END__
190
+
191
+
192
+ 2. Address Prefix ORF-Type
193
+
194
+ The Address Prefix ORF-Type allows one to express ORFs in terms of
195
+ address prefixes. That is, it provides address prefix based route
196
+ filtering, including prefix length or range based matching, as well
197
+ as wild-card address prefix matching.
198
+
199
+ Conceptually an Address Prefix ORF entry consists of the fields
200
+ <Sequence, Match, Length, Prefix, Minlen, Maxlen>.
201
+
202
+ The "Sequence" field specifies the relative ordering of the entry
203
+ among all the Address Prefix ORF entries.
204
+
205
+ The "Match" field specifies whether this entry is "PERMIT" (value 0),
206
+ or "DENY" (value 1).
207
+
208
+ The "Length" field indicates the length in bits of the address
209
+ prefix. A length of zero indicates a prefix that matches all (as
210
+ specified by the address family) addresses (with prefix itself of
211
+ zero octets).
212
+
213
+ The "Prefix" field contains an address prefix of an address family.
214
+
215
+ The "Minlen" field indicates the minimum prefix length in bits that
216
+ is required for "matching". The field is considered as un-specified
217
+ with value 0.
218
+
219
+ The "Maxlen" field indicates the maximum prefix length in bits that
220
+ is required for "matching". The field is considered as un-specified
221
+ with value 0.
222
+
223
+ The fields "Sequence", "Length", "Minlen", and "Maxlen" are all
224
+ unsigned integers.
225
+
226
+ This document imposes the following requirement on the values of
227
+ these fields:
228
+
229
+ 0 <= Length < Minlen <= Maxlen
230
+
231
+ In addition, the "Maxlen" must be no more than the maximum length (in
232
+ bits) of a host address for a given address family [BGP-MP].
233
+
234
+
235
+ 3. Address Prefix ORF Encoding
236
+
237
+ The value of the ORF-Type for the Address Prefix ORF-Type is 64.
238
+
239
+ An Address Prefix ORF entry is encoded as follows. The "Match" field
240
+ of the entry is encoded in the "Match" field of the common part [BGP-
241
+ ORF], and the remaining fields of the entry is encoded in the "Type
242
+ specific part" as shown in Figure 1.
243
+
244
+
245
+ +--------------------------------+
246
+ | Sequence (4 octets) |
247
+ +--------------------------------+
248
+ | Minlen (1 octet) |
249
+ +--------------------------------+
250
+ | Maxlen (1 octet) |
251
+ +--------------------------------+
252
+ | Length (1 octet) |
253
+ +--------------------------------+
254
+ | Prefix (variable length) |
255
+ +--------------------------------+
256
+
257
+ Figure 1: Address Prefix ORF Encoding
258
+
259
+
260
+ Note that the Prefix field contains the address prefix followed by
261
+ enough trailing bits to make the end of the field fall on an octet
262
+ boundary. The value of the trailing bits is irrelevant.
263
+
data/bgp/rd.rb ADDED
@@ -0,0 +1,107 @@
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/common'
25
+ module BGP
26
+ class Rd
27
+ attr_reader :admin, :assign
28
+ def bit_length ; 64 ; end
29
+ def initialize(*args)
30
+ if args.size==1 and args[0].is_a?(String) and args[0].is_packed?
31
+ parse(args[0])
32
+ elsif args[0].is_a?(self.class)
33
+ parse(args[0].encode, *args[1..-1])
34
+ elsif args.empty?
35
+ @enc_type, @admin, @assign = [0]*3
36
+ elsif args.size==3
37
+ admin, assign, @enc_type = args
38
+ case @enc_type
39
+ when 0
40
+ @admin, @assign,@enc_type = admin, assign, 0
41
+ when 1
42
+ @enc_type = 1
43
+ @admin = IPAddr.new(admin)
44
+ @assign = assign
45
+ when 2
46
+ @admin, @assign, @enc_type, = admin, assign, 2
47
+ end
48
+ elsif args.size==2
49
+ admin, assign = args
50
+ if admin.is_a?(String)
51
+ @admin, @assign, @enc_type = IPAddr.new(admin), assign, 1
52
+ elsif assign.is_a?(String)
53
+ @admin, @assign, @enc_type, = admin, IPAddr.new(assign).to_i, 2
54
+ else
55
+ @admin, @assign, @enc_type, = admin, assign, 0
56
+ end
57
+ end
58
+ end
59
+
60
+ def encode
61
+ case @enc_type
62
+ when 0
63
+ [@enc_type, @admin, @assign].pack('nnN')
64
+ when 1
65
+ [@enc_type, @admin.hton, @assign].pack('na*n')
66
+ when 2
67
+ [@enc_type, @admin, @assign].pack('nNn')
68
+ end
69
+ end
70
+
71
+ def parse(s)
72
+ case s[0,2].unpack('n')[0]
73
+ when 0
74
+ @enc_type, @admin, @assign = s.unpack('nnN')
75
+ when 1
76
+ @enc_type, admin, @assign = s.unpack('na4n')
77
+ @admin = IPAddr.new_ntoh(admin)
78
+ when 2
79
+ @enc_type, @admin, @assign = s.unpack('nNn')
80
+ else
81
+ puts "Bogus rd ? #{s.unpack('H*')}"
82
+ end
83
+ end
84
+
85
+ def to_s(verbose=true)
86
+ if verbose
87
+ case @enc_type
88
+ when 0 ; format "RD=%d:%d (0x%02x 0x%04x)", @admin, @assign, @assign, @assign
89
+ when 1 ; format "RD=%s:%d (0x%04x 0x%02x)", @admin, @assign, @admin.to_i, @assign
90
+ when 2 ; format "RD=%d:%d (0x%04x 0x%02x)", @admin, @assign, @admin, @assign
91
+ end
92
+ else
93
+ case @enc_type
94
+ when 0 ; format "RD=%d:%d", @admin, @assign
95
+ when 1 ; format "RD=%s:%d", @admin, @assign
96
+ when 2 ; format "RD=%d:%d", @admin, @assign
97
+ end
98
+ end
99
+ end
100
+
101
+ def encoding_type?
102
+ @enc_type
103
+ end
104
+
105
+ end
106
+ end
107
+ load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
data/examples/bgp ADDED
@@ -0,0 +1,65 @@
1
+ #--
2
+ #
3
+ # Copyright 2008, 2009 Jean-Michel Esnault.
4
+ # All rights reserved.
5
+ # See LICENSE.txt for permissions.
6
+ #
7
+ #++
8
+
9
+ require 'bgp4r'
10
+ include BGP
11
+
12
+ # Start loggin
13
+ Log.create
14
+ Log.level=Logger::DEBUG
15
+
16
+ # Create a neighbor and set optional capabilities.
17
+ neighbor = Neighbor.new \
18
+ :version=> 4,
19
+ :my_as=> 100,
20
+ :remote_addr => '192.168.1.199',
21
+ :local_addr => '192.168.1.5',
22
+ :id=> '1.1.1.1', :holdtime=> 180
23
+
24
+ neighbor.capability :as4_byte
25
+ neighbor.capability :route_refresh
26
+ neighbor.capability :route_refresh, 128
27
+ neighbor.capability :mbgp, :ipv4, :unicast
28
+ neighbor.capability :mbgp, :ipv4, :multicast
29
+
30
+ # A call back to handle received messages we are interested in.
31
+ def self.update(msg)
32
+ case msg.class.to_s
33
+ when /Notification/
34
+ Log.warn "Going down !"
35
+ # Ignore uninterested ones.
36
+ # when /Open/
37
+ # when /Keepalive/
38
+ when /Update/
39
+ Log.info "RecvUpdate\n#{m}"
40
+ end
41
+ end
42
+
43
+ neighbor.add_observer(self)
44
+
45
+ # Start peering (will block til the session is established)
46
+ neighbor.start :auto_retry
47
+
48
+ # An BGP Update object
49
+ an_update = Update.new(
50
+ Path_attribute.new(
51
+ Origin.new(2),
52
+ Next_hop.new('192.168.1.5'),
53
+ Multi_exit_disc.new(100),
54
+ Local_pref.new(100),
55
+ As_path.new(400,300,200),
56
+ Communities.new('1311:1 311:59 2805:64')
57
+ ),
58
+ Nlri.new('77.0.0.0/17', '78.0.0.0/18', '79.0.0.0/19')
59
+ )
60
+
61
+ # Ship it!
62
+ neighbor.send_message an_update
63
+
64
+ # Keep session up.
65
+ Thread.stop