jesnault-bgp4r 0.0.2 → 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.
- 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 +84 -11
data/bgp/common.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
# This file is part of BGP4R.
|
2
|
+
#
|
3
|
+
# BGP4R is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# BGP4R is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with Foobar. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'ipaddr'
|
17
|
+
require 'logger'
|
18
|
+
|
19
|
+
class IPAddr
|
20
|
+
alias encode hton
|
21
|
+
|
22
|
+
def self.create(arg)
|
23
|
+
if arg.is_a?(String) and arg.is_packed?
|
24
|
+
IPAddr.new_ntoh(arg)
|
25
|
+
elsif arg.is_a?(Integer)
|
26
|
+
IPAddr.new_ntoh([arg].pack('N'))
|
27
|
+
elsif arg.is_a?(Array) and arg[0].is_a?(Fixnum)
|
28
|
+
IPAddr.new_ntoh([arg].pack('C*'))
|
29
|
+
else
|
30
|
+
IPAddr.new(arg)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#TODO: if not used, get rid of it.
|
35
|
+
def self.new_nlri4(arg)
|
36
|
+
if arg.is_a?(String) and arg.is_packed?
|
37
|
+
arg +=([0]*3).pack('C*')
|
38
|
+
plen, *nlri = arg.unpack('CC4')
|
39
|
+
ipaddr = nlri.collect { |n| n.to_s }.join('.') + "/" + plen .to_s
|
40
|
+
IPAddr.new(ipaddr)
|
41
|
+
else
|
42
|
+
IPAddr.new(arg)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def _mlen_
|
47
|
+
m = @mask_addr
|
48
|
+
len = ipv6? ? 128 : 32
|
49
|
+
loop do
|
50
|
+
break if m & 1 > 0
|
51
|
+
m = m >> 1
|
52
|
+
len += -1
|
53
|
+
end
|
54
|
+
len
|
55
|
+
end
|
56
|
+
|
57
|
+
def mlen
|
58
|
+
@_jme_mlen_ ||= _mlen_
|
59
|
+
end
|
60
|
+
|
61
|
+
def _generate_network_inc_
|
62
|
+
max_len = ipv4? ? 32 : 128
|
63
|
+
Proc.new { |n| n*(2**(max_len - mlen)) }
|
64
|
+
end
|
65
|
+
def +(i)
|
66
|
+
[IPAddr.create(to_i + i).to_s, mlen].join("/")
|
67
|
+
end
|
68
|
+
def ^(i)
|
69
|
+
@increment ||= _generate_network_inc_
|
70
|
+
[IPAddr.create(to_i + @increment.call(i)).to_s, mlen].join("/")
|
71
|
+
end
|
72
|
+
private :_generate_network_inc_
|
73
|
+
|
74
|
+
def netmask
|
75
|
+
if ipv4?
|
76
|
+
[@mask_addr].pack('N').unpack('C4').collect { |x| x.to_s}.join('.')
|
77
|
+
else
|
78
|
+
#TODO netmask ipv6
|
79
|
+
@mask_addr
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
class Object
|
87
|
+
def to_shex(*args)
|
88
|
+
self.respond_to?(:encode) ? self.encode(*args).unpack('H*')[0] : ""
|
89
|
+
end
|
90
|
+
alias to_s_hexlify to_shex
|
91
|
+
def to_shex4(*args)
|
92
|
+
self.respond_to?(:encode4) ? self.encode4(*args).unpack('H*')[0] : ""
|
93
|
+
end
|
94
|
+
def to_shex_len(len, *args)
|
95
|
+
s = to_shex(*args)
|
96
|
+
"#{s[0..len]}#{s.size>len ? '...' : ''}"
|
97
|
+
end
|
98
|
+
def to_shex4_len(len, *args)
|
99
|
+
s = to_shex4(*args)
|
100
|
+
"#{s[0..len]}#{s.size>len ? '...' : ''}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Array
|
105
|
+
alias_method :old_pack, :pack
|
106
|
+
def pack(*args)
|
107
|
+
s = self.old_pack(*args)
|
108
|
+
s.instance_eval { @__is_packed__ = true }
|
109
|
+
s
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class String
|
114
|
+
def is_packed?
|
115
|
+
defined?(@__is_packed__) and @__is_packed__
|
116
|
+
end
|
117
|
+
def is_packed
|
118
|
+
@__is_packed__ = true
|
119
|
+
self
|
120
|
+
end
|
121
|
+
alias packed? :is_packed?
|
122
|
+
|
123
|
+
def hexlify
|
124
|
+
return self unless is_packed?
|
125
|
+
s=self.dup
|
126
|
+
ls=[""]
|
127
|
+
n=0
|
128
|
+
while s.size>0
|
129
|
+
l = s.slice!(0,16)
|
130
|
+
ls << format("0x%4.4x: %s", n,
|
131
|
+
l.unpack("n#{l.size/2}").collect { |x| format("%4.4x",x) }.join(' '))
|
132
|
+
n+=1
|
133
|
+
end
|
134
|
+
ls
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
class Log < Logger
|
140
|
+
private_class_method :new
|
141
|
+
@@logger = nil
|
142
|
+
def initialize(s)
|
143
|
+
super(s)
|
144
|
+
@@time=Time.now
|
145
|
+
self.datetime_format = "%M:%S"
|
146
|
+
self.level = Logger::INFO
|
147
|
+
end
|
148
|
+
def Log.time_reset
|
149
|
+
@time = Time.now
|
150
|
+
end
|
151
|
+
def Log.create(s=STDERR)
|
152
|
+
@@logger ||= new(s)
|
153
|
+
end
|
154
|
+
def Log.set_filename(s)
|
155
|
+
@@logger = new(s)
|
156
|
+
end
|
157
|
+
def Log.level=(level)
|
158
|
+
return unless (0..4) === level
|
159
|
+
@@logger.level=(level)
|
160
|
+
end
|
161
|
+
def Log.level
|
162
|
+
case @@logger.level
|
163
|
+
when Logger::INFO ; "(#{Logger::INFO }) 'INFO'"
|
164
|
+
when Logger::DEBUG ; "(#{Logger::DEBUG }) 'DEBUG'"
|
165
|
+
when Logger::WARN ; "(#{Logger::WARN }) 'WARN'"
|
166
|
+
when Logger::ERROR ; "(#{Logger::ERROR }) 'ERROR'"
|
167
|
+
when Logger::FATAL ; "(#{Logger::FATAL }) 'FATAL'"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
def Log.clear
|
171
|
+
`rm #{Log.filename}`
|
172
|
+
Log.set_filename(Log.filename)
|
173
|
+
end
|
174
|
+
def Log.filename
|
175
|
+
@@logger.instance_eval { @logdev.filename }
|
176
|
+
end
|
177
|
+
def Log.start(*arg)
|
178
|
+
Log.create(*arg)
|
179
|
+
end
|
180
|
+
def Log.info(txt)
|
181
|
+
@@logger.info(txt) unless @@logger.nil?
|
182
|
+
end
|
183
|
+
def Log.fatal(txt)
|
184
|
+
@@logger.fatal(txt) unless @@logger.nil?
|
185
|
+
end
|
186
|
+
def Log.error(txt)
|
187
|
+
@@logger.error(txt) unless @@logger.nil?
|
188
|
+
end
|
189
|
+
def Log.debug(txt)
|
190
|
+
@@logger.debug(txt) unless @@logger.nil?
|
191
|
+
end
|
192
|
+
def Log.warn(txt)
|
193
|
+
@@logger.warn(txt) unless @@logger.nil?
|
194
|
+
end
|
195
|
+
def Log.<<(txt)
|
196
|
+
elapsed = Time.now - @@time
|
197
|
+
@@logger << "<< #{format "%4.6f", elapsed}: #{txt}\n" unless @@logger.nil?
|
198
|
+
end
|
199
|
+
def Log.>>(txt)
|
200
|
+
elapsed = Time.now.to_f - @@time.to_f
|
201
|
+
@@logger << ">> #{format "%4.6f", elapsed}: #{txt}\n" unless @@logger.nil?
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
data/bgp/communities.rb
ADDED
@@ -0,0 +1,139 @@
|
|
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
|
+
|
27
|
+
module BGP
|
28
|
+
|
29
|
+
class Communities < Attr
|
30
|
+
|
31
|
+
class Community
|
32
|
+
|
33
|
+
def initialize(arg)
|
34
|
+
if arg.is_a?(Symbol)
|
35
|
+
case arg
|
36
|
+
when :no_export ; @value=0xFFFFFF01
|
37
|
+
when :no_advertise ; @value=0xFFFFFF02
|
38
|
+
when :no_export_sub_confed ; @value=0xFFFFFF03
|
39
|
+
when :no_peer ; @value=0xFFFFFF04
|
40
|
+
else
|
41
|
+
raise ArgumentError, "invalid argument #{val}"
|
42
|
+
end
|
43
|
+
elsif arg.is_a?(String) and arg.split(':').size==2
|
44
|
+
self.value=arg.split(':').collect { |n| n.to_i }.pack('n2').unpack('N')[0]
|
45
|
+
else
|
46
|
+
self.value=arg
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def value=(val)
|
51
|
+
raise ArgumentError, "invalid argument #{val}" unless val.is_a?(Fixnum) or val.is_a?(Bignum)
|
52
|
+
@value=val
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_i
|
56
|
+
@value
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
[@value >> 16, @value & 0xffff].join(':')
|
61
|
+
end
|
62
|
+
|
63
|
+
# The community attribute values ranging from 0x0000000 through
|
64
|
+
# 0x0000FFFF and 0xFFFF0000 through 0xFFFFFFFF are hereby reserved.
|
65
|
+
def is_reserved?
|
66
|
+
(0x0000000..0x0000FFFF ) === @value or (0xFFFF0000..0xFFFFFFFF) === @value
|
67
|
+
end
|
68
|
+
|
69
|
+
def encode
|
70
|
+
[@value].pack('N')
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize(*args)
|
76
|
+
@flags, @type = OPTIONAL_TRANSITIVE, COMMUNITIES
|
77
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
78
|
+
parse(args[0])
|
79
|
+
elsif args[0].is_a?(self.class) and args[0].respond_to?(:encode)
|
80
|
+
parse(args[0].encode, *args[1..-1])
|
81
|
+
else
|
82
|
+
add(*args)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def add(*args)
|
87
|
+
@communities ||=[]
|
88
|
+
args.flatten.each do |arg|
|
89
|
+
if arg.is_a?(String) and arg.split(' ').size>1
|
90
|
+
arg.split.each { |v| @communities << Community.new(v) }
|
91
|
+
elsif arg.is_a?(String) and arg.split(',').size>1
|
92
|
+
arg.split(',').each { |v| @communities << Community.new(v) }
|
93
|
+
elsif arg.is_a?(Community)
|
94
|
+
@communities << arg
|
95
|
+
else
|
96
|
+
@communities << Community.new(arg)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
alias << add
|
101
|
+
|
102
|
+
def communities
|
103
|
+
@communities.collect { |comm| comm.to_s }.join(' ')
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_s(method=:default)
|
107
|
+
super(communities, method)
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_ary
|
111
|
+
@communities.collect { |c| c.to_i }
|
112
|
+
end
|
113
|
+
|
114
|
+
def encode
|
115
|
+
super(@communities.collect { |comm| comm.encode }.join)
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse(s)
|
119
|
+
@flags, @type, len, value=super(s)
|
120
|
+
self << value.unpack("N#{len/4}")
|
121
|
+
end
|
122
|
+
|
123
|
+
def sort
|
124
|
+
Communities.new(to_ary.sort)
|
125
|
+
end
|
126
|
+
|
127
|
+
def sort!
|
128
|
+
@communities = @communities.sort_by { |c| c.to_i }
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
def <=>(other)
|
133
|
+
self.sort.to_shex <=> other.sort.to_shex
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
@@ -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/attribute'
|
25
|
+
require 'bgp/extended_community'
|
26
|
+
|
27
|
+
module BGP
|
28
|
+
|
29
|
+
class Extended_communities < Attr
|
30
|
+
|
31
|
+
attr_reader :communities
|
32
|
+
|
33
|
+
def initialize(*args)
|
34
|
+
@flags, @type = OPTIONAL_TRANSITIVE, EXTENDED_COMMUNITY
|
35
|
+
|
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
|
+
else
|
41
|
+
add(*args)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def add(*args)
|
46
|
+
@communities ||=[]
|
47
|
+
args.flatten.each do |arg|
|
48
|
+
if arg.is_a?(String) and arg.split(' ').size>1
|
49
|
+
arg.split.each { |v| @communities << Extended_community.factory(v) }
|
50
|
+
elsif arg.is_a?(String) and arg.split(',').size>1
|
51
|
+
arg.split(',').each { |v| @communities << Extended_community.factory(v) }
|
52
|
+
elsif arg.is_a?(Extended_community)
|
53
|
+
@communities << arg
|
54
|
+
else
|
55
|
+
@communities << Extended_community.factory(arg)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
self
|
59
|
+
end
|
60
|
+
alias << add
|
61
|
+
|
62
|
+
def extended_communities
|
63
|
+
len = @communities.size*8
|
64
|
+
s=[]
|
65
|
+
s << ''
|
66
|
+
s << " Carried Extended communities"
|
67
|
+
s << " " + @communities.collect { |c| c.to_s }.join("\n ")
|
68
|
+
s.join("\n")
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s(method=:default)
|
72
|
+
super(extended_communities, method)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_arr
|
76
|
+
@communities.collect { |c| c.to_i }
|
77
|
+
end
|
78
|
+
|
79
|
+
def encode
|
80
|
+
super(@communities.collect { |comm| comm.encode }.join)
|
81
|
+
end
|
82
|
+
|
83
|
+
def parse(s)
|
84
|
+
@flags, @type, len, value=super(s)
|
85
|
+
while value.size>0
|
86
|
+
self << Extended_community.factory(value.slice!(0,8).is_packed)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def sort
|
91
|
+
Extended_communities.new(*to_arr.sort)
|
92
|
+
end
|
93
|
+
|
94
|
+
def sort!
|
95
|
+
@communities = @communities.sort_by { |c| c.to_i }
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def <=>(other)
|
100
|
+
sort.to_shex <=> other.sort.to_shex
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
|
@@ -0,0 +1,254 @@
|
|
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
|
+
require 'bgp/attribute'
|
26
|
+
|
27
|
+
module BGP
|
28
|
+
|
29
|
+
module ATTR::XTENDED_COMMUNITY
|
30
|
+
|
31
|
+
ROUTE_TARGET = 2
|
32
|
+
ROUTE_ORIGIN = 3
|
33
|
+
OSPF_DOMAIN_ID = 5
|
34
|
+
OSPF_ROUTER_ID = 7
|
35
|
+
BGP_DATA_COLLECT = 8
|
36
|
+
|
37
|
+
IANA_AUTHORITY_BIT = 0x8
|
38
|
+
NON_TRANSITIVE = 0x4
|
39
|
+
|
40
|
+
TWO_OCTET_AS = 0
|
41
|
+
IPV4_ADDR = 1
|
42
|
+
OPAQUE = 3
|
43
|
+
|
44
|
+
def _encoded_value_
|
45
|
+
case @type & 3
|
46
|
+
when TWO_OCTET_AS
|
47
|
+
[@global, @local].pack('nN')
|
48
|
+
when IPV4_ADDR
|
49
|
+
[@global, @local].pack('Nn')
|
50
|
+
when OPAQUE
|
51
|
+
[@global].pack('H12')
|
52
|
+
else
|
53
|
+
raise RuntimeError, "bogus type: #{@type}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def encode
|
58
|
+
[@type, @subtype, _encoded_value_].pack('CCa6')
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse(s)
|
62
|
+
@type, @subtype = s.slice!(0,2).unpack('CC')
|
63
|
+
case @type & 3
|
64
|
+
when TWO_OCTET_AS ; @global, @local = s.unpack('nN')
|
65
|
+
when IPV4_ADDR
|
66
|
+
@global, @local = s.unpack('Nn')
|
67
|
+
when OPAQUE
|
68
|
+
@global = s.unpack('H12')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def is_opaque?
|
73
|
+
@type & OPAQUE > 0
|
74
|
+
end
|
75
|
+
|
76
|
+
def is_ipv4_addr?
|
77
|
+
@type & IPV4_ADDR > 0
|
78
|
+
end
|
79
|
+
|
80
|
+
def is_two_octet_asn?
|
81
|
+
@type & 3 == TWO_OCTET_AS
|
82
|
+
end
|
83
|
+
|
84
|
+
def two_octet
|
85
|
+
@type &= ~3
|
86
|
+
end
|
87
|
+
|
88
|
+
def ipv4_addr
|
89
|
+
@type &= ~3
|
90
|
+
@type |= 1
|
91
|
+
end
|
92
|
+
|
93
|
+
def opaque
|
94
|
+
@type |= 3
|
95
|
+
end
|
96
|
+
|
97
|
+
def non_transitive
|
98
|
+
@type |= 0x40
|
99
|
+
end
|
100
|
+
|
101
|
+
def transitive
|
102
|
+
@type &= ~0x40
|
103
|
+
end
|
104
|
+
|
105
|
+
def is_transitive?
|
106
|
+
@type & 0x40 == 0
|
107
|
+
end
|
108
|
+
|
109
|
+
def non_transitive?
|
110
|
+
not is_transitive?
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_i
|
114
|
+
encode.unpack('H*')[0].to_i(16)
|
115
|
+
end
|
116
|
+
|
117
|
+
def <=>(other)
|
118
|
+
to_i <=> other.to_i
|
119
|
+
end
|
120
|
+
|
121
|
+
def name
|
122
|
+
self.class.to_s.split('::').last.gsub('_',' ')
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
class Extended_community
|
129
|
+
include ATTR::XTENDED_COMMUNITY
|
130
|
+
include Comparable
|
131
|
+
|
132
|
+
def self.factory(_s)
|
133
|
+
if _s.is_a?(Bignum) or _s.is_a?(Fixnum)
|
134
|
+
s = [format("%16.16x",_s)].pack('H*')
|
135
|
+
else
|
136
|
+
s = _s
|
137
|
+
end
|
138
|
+
type, subtype, value = s.unpack('CCa6')
|
139
|
+
case subtype
|
140
|
+
when ROUTE_TARGET ; Route_target.new(s)
|
141
|
+
when ROUTE_ORIGIN ; Route_origin.new(s)
|
142
|
+
when OSPF_DOMAIN_ID ; Ospf_domain_id.new(s)
|
143
|
+
when OSPF_ROUTER_ID ; Ospf_router_id.new(s)
|
144
|
+
when BGP_DATA_COLLECT ; Bgp_data_collect.new(s)
|
145
|
+
else
|
146
|
+
puts "too bad type #{type}, subtype #{subtype} : #{s.unpack('H*')}"
|
147
|
+
Extended_community.new(s)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def initialize(*args)
|
152
|
+
@type=TWO_OCTET_AS
|
153
|
+
if args.size==1 and args[0].is_a?(String) and args[0].is_packed?
|
154
|
+
parse(args[0])
|
155
|
+
elsif args.size==3
|
156
|
+
@type, @subtype, value = args
|
157
|
+
raise ArgumentError, "invalid argument #{args.inspect}" unless instance_of?(Opaque)
|
158
|
+
@type |= OPAQUE
|
159
|
+
@global, @local=value, nil
|
160
|
+
elsif args.size==4
|
161
|
+
raise ArgumentError, "This is a base class and should not be instanciated" if instance_of?(Extended_community)
|
162
|
+
@type, @subtype, @global, @local = args
|
163
|
+
if @global.is_a?(String) and @local.is_a?(Fixnum)
|
164
|
+
@type |= IPV4_ADDR
|
165
|
+
@global = IPAddr.new(@global).to_i
|
166
|
+
end
|
167
|
+
elsif args.size==1 and args[0].is_a?(Bignum)
|
168
|
+
parse([s].pack('H*'))
|
169
|
+
elsif args.empty?
|
170
|
+
@type, @subtype, @global, @local = 0,0,0,0
|
171
|
+
else
|
172
|
+
raise ArgumentError, "invalid arg #{args.inspect}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_s
|
177
|
+
case @type & 3
|
178
|
+
when TWO_OCTET_AS
|
179
|
+
"#{name}: #{@global}:#{@local}"
|
180
|
+
when IPV4_ADDR
|
181
|
+
"#{name}: #{IPAddr.create(@global)}:#{@local}"
|
182
|
+
when OPAQUE
|
183
|
+
"#{name}: #{@global}"
|
184
|
+
else
|
185
|
+
raise RuntimeError, "bogus type: #{@type}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
class Route_target < Extended_community
|
192
|
+
def initialize(*args)
|
193
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
194
|
+
super(*args)
|
195
|
+
else
|
196
|
+
super(0, ROUTE_TARGET, *args)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class Route_origin < Extended_community
|
202
|
+
def initialize(*args)
|
203
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
204
|
+
super(*args)
|
205
|
+
else
|
206
|
+
super(0,ROUTE_ORIGIN,*args)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
class Ospf_domain_id < Extended_community
|
212
|
+
def initialize(*args)
|
213
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
214
|
+
super(*args)
|
215
|
+
else
|
216
|
+
args += [0]
|
217
|
+
super(1,OSPF_DOMAIN_ID,*args)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
class Ospf_router_id < Extended_community
|
223
|
+
def initialize(*args)
|
224
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
225
|
+
super(*args)
|
226
|
+
else
|
227
|
+
args += [0]
|
228
|
+
super(1,OSPF_ROUTER_ID,*args)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
class Bgp_data_collect < Extended_community
|
234
|
+
def initialize(*args)
|
235
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
236
|
+
super(*args)
|
237
|
+
else
|
238
|
+
super(0,BGP_DATA_COLLECT,*args)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class Opaque < Extended_community
|
244
|
+
def initialize(*args)
|
245
|
+
if args[0].is_a?(String) and args[0].is_packed?
|
246
|
+
super(*args)
|
247
|
+
else
|
248
|
+
raise ArgumentError, "not an opaque extended community" if [2,3,5,7,8].include?(args[0])
|
249
|
+
super(0,*args)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|