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