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