bgp4r 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/README.rdoc +1 -10
  2. data/bgp/io.rb +4 -2
  3. data/bgp/messages/capability.rb +176 -0
  4. data/bgp/messages/keepalive.rb +30 -0
  5. data/bgp/messages/markers.rb +10 -0
  6. data/bgp/messages/message.rb +85 -0
  7. data/bgp/messages/messages.rb +17 -0
  8. data/bgp/messages/notification.rb +116 -0
  9. data/bgp/messages/open.rb +117 -0
  10. data/bgp/messages/route_refresh.rb +181 -0
  11. data/bgp/messages/update.rb +148 -0
  12. data/bgp/neighbor.rb +20 -11
  13. data/bgp/nlris/inet.rb +18 -0
  14. data/bgp/{label.rb → nlris/label.rb} +1 -1
  15. data/bgp/nlris/labeled.rb +39 -0
  16. data/bgp/nlris/nlri.rb +154 -0
  17. data/bgp/{attributes.rb → nlris/nlris.rb} +11 -13
  18. data/bgp/nlris/prefix.rb +33 -0
  19. data/bgp/{rd.rb → nlris/rd.rb} +1 -1
  20. data/bgp/nlris/vpn.rb +68 -0
  21. data/bgp/optional_parameters/as4.rb +59 -0
  22. data/bgp/optional_parameters/capabilities.rb +13 -0
  23. data/bgp/optional_parameters/capability.rb +145 -0
  24. data/bgp/optional_parameters/dynamic.rb +37 -0
  25. data/bgp/optional_parameters/graceful_restart.rb +116 -0
  26. data/bgp/optional_parameters/mbgp.rb +97 -0
  27. data/bgp/optional_parameters/optional_parameter.rb +76 -0
  28. data/bgp/optional_parameters/orf.rb +90 -0
  29. data/bgp/optional_parameters/route_refresh.rb +36 -0
  30. data/bgp/{prefix_orf.rb → orfs/prefix_orf.rb} +4 -10
  31. data/bgp/{aggregator.rb → path_attributes/aggregator.rb} +2 -2
  32. data/bgp/{as_path.rb → path_attributes/as_path.rb} +2 -2
  33. data/bgp/{atomic_aggregate.rb → path_attributes/atomic_aggregate.rb} +2 -2
  34. data/bgp/{attribute.rb → path_attributes/attribute.rb} +2 -2
  35. data/bgp/path_attributes/attributes.rb +21 -0
  36. data/bgp/{cluster_list.rb → path_attributes/cluster_list.rb} +2 -2
  37. data/bgp/{communities.rb → path_attributes/communities.rb} +2 -2
  38. data/bgp/{extended_communities.rb → path_attributes/extended_communities.rb} +3 -3
  39. data/bgp/{extended_community.rb → path_attributes/extended_community.rb} +1 -1
  40. data/bgp/{local_pref.rb → path_attributes/local_pref.rb} +2 -2
  41. data/bgp/{mp_reach.rb → path_attributes/mp_reach.rb} +3 -69
  42. data/bgp/path_attributes/mp_unreach.rb +97 -0
  43. data/bgp/{multi_exit_disc.rb → path_attributes/multi_exit_disc.rb} +2 -2
  44. data/bgp/{next_hop.rb → path_attributes/next_hop.rb} +2 -2
  45. data/bgp/{origin.rb → path_attributes/origin.rb} +2 -2
  46. data/bgp/{originator_id.rb → path_attributes/originator_id.rb} +2 -2
  47. data/bgp/{path_attribute.rb → path_attributes/path_attribute.rb} +6 -7
  48. data/bgp4r.gemspec +127 -67
  49. data/bgp4r.rb +5 -25
  50. data/examples/routegen +1 -1
  51. data/examples/routegen.yml +21 -5
  52. data/examples/simple.rb +4 -4
  53. data/examples/unit-testing/malformed_update.rb +1 -1
  54. data/examples/unit-testing/unknown_transitive_attr.rb +18 -10
  55. data/test/messages/capability_test.rb +113 -0
  56. data/test/messages/keepalive_test.rb +34 -0
  57. data/test/messages/markers_test.rb +33 -0
  58. data/test/messages/message_test.rb +43 -0
  59. data/test/messages/notification_test.rb +49 -0
  60. data/test/messages/open_test.rb +98 -0
  61. data/test/messages/route_refresh_test.rb +77 -0
  62. data/test/messages/update_test.rb +133 -0
  63. data/test/neighbor_test.rb +8 -9
  64. data/test/nlris/inet_test.rb +43 -0
  65. data/test/{label_test.rb → nlris/labeled_test.rb} +1 -1
  66. data/test/{nlri_test.rb → nlris/nlri_test.rb} +5 -1
  67. data/test/{rd_test.rb → nlris/rd_test.rb} +1 -2
  68. data/test/optional_parameters/as4_test.rb +34 -0
  69. data/test/optional_parameters/capability_test.rb +69 -0
  70. data/test/optional_parameters/dynamic_test.rb +34 -0
  71. data/test/optional_parameters/graceful_restart_test.rb +23 -0
  72. data/test/optional_parameters/mbgp_test.rb +35 -0
  73. data/test/optional_parameters/optional_parameter_test.rb +51 -0
  74. data/test/optional_parameters/orf_test.rb +42 -0
  75. data/test/optional_parameters/route_refresh_test.rb +32 -0
  76. data/test/{prefix_orf_test.rb → orfs/prefix_orf_test.rb} +2 -1
  77. data/test/{aggregator_test.rb → path_attributes/aggregator_test.rb} +1 -1
  78. data/test/{as_path_test.rb → path_attributes/as_path_test.rb} +1 -1
  79. data/test/{atomic_aggregate_test.rb → path_attributes/atomic_aggregate_test.rb} +1 -1
  80. data/test/{attribute_test.rb → path_attributes/attribute_test.rb} +2 -2
  81. data/test/{cluster_list_test.rb → path_attributes/cluster_list_test.rb} +1 -1
  82. data/test/{communities_test.rb → path_attributes/communities_test.rb} +1 -1
  83. data/test/{extended_communities_test.rb → path_attributes/extended_communities_test.rb} +1 -1
  84. data/test/{extended_community_test.rb → path_attributes/extended_community_test.rb} +1 -1
  85. data/test/{local_pref_test.rb → path_attributes/local_pref_test.rb} +1 -1
  86. data/test/{mp_reach_test.rb → path_attributes/mp_reach_test.rb} +1 -37
  87. data/test/path_attributes/mp_unreach_test.rb +67 -0
  88. data/test/{multi_exit_disc_test.rb → path_attributes/multi_exit_disc_test.rb} +1 -1
  89. data/test/{next_hop_test.rb → path_attributes/next_hop_test.rb} +1 -1
  90. data/test/{origin_test.rb → path_attributes/origin_test.rb} +2 -1
  91. data/test/{originator_id_test.rb → path_attributes/originator_id_test.rb} +1 -1
  92. data/test/{path_attribute_test.rb → path_attributes/path_attribute_test.rb} +2 -2
  93. metadata +122 -67
  94. data/bgp/message.rb +0 -921
  95. data/bgp/nlri.rb +0 -303
  96. data/bgp/version.rb +0 -3
  97. data/examples/unit-testing/keepalive_set_to_zeo.rb +0 -64
  98. data/test/message_test.rb +0 -347
  99. /data/bgp/{orf.rb → orfs/orf.rb} +0 -0
@@ -0,0 +1,181 @@
1
+ # Route-REFRESH Message
2
+ #
3
+ # The ROUTE-REFRESH message is a new BGP message type defined as
4
+ # follows:
5
+ #
6
+ # Type: 5 - ROUTE-REFRESH
7
+ #
8
+ # Message Format: One <AFI, SAFI> encoded as
9
+ #
10
+ # 0 7 15 23 31
11
+ # +-------+-------+-------+-------+
12
+ # | AFI | Res. | SAFI |
13
+ # +-------+-------+-------+-------+
14
+ #
15
+
16
+
17
+ require 'bgp/messages/message'
18
+
19
+ module BGP
20
+
21
+ class Route_refresh < Message
22
+ attr_reader :afi, :safi
23
+ def initialize(*args)
24
+ @msg_type=ROUTE_REFRESH
25
+ if args.size==1 and args[0].is_a?(String) and args[0].is_packed?
26
+ parse(args[0])
27
+ elsif args[0].is_a?(self.class)
28
+ parse(args[0].encode, *args[1..-1])
29
+ elsif args.size==1 and args[0].is_a?(Hash)
30
+ self.afi = args[0][:afi] if args[0][:afi]
31
+ self.safi = args[0][:safi] if args[0][:safi]
32
+ else
33
+ @afi, @safi=args
34
+ end
35
+ end
36
+
37
+ def afi=(val)
38
+ raise ArgumentError, "invalid argument" unless val.is_a?(Fixnum) and (0..0xffff) === val
39
+ @afi=val
40
+ end
41
+
42
+ def safi=(val)
43
+ raise ArgumentError, "invalid argument" unless val.is_a?(Fixnum) and (0..0xff) === val
44
+ @safi=val
45
+ end
46
+
47
+ def encode
48
+ # default to ipv4 and unicast when not set
49
+ @afi ||=1
50
+ @safi ||=1
51
+ super([@afi, 0, @safi].pack('nCC'))
52
+ end
53
+
54
+ def parse(s)
55
+ @afi, reserved, @safi= super(s).unpack('nCC')
56
+ end
57
+
58
+ def to_hash
59
+ {:afi=> @afi, :safi=> @safi}
60
+ end
61
+
62
+ def to_s
63
+ msg = self.encode
64
+ "Route Refresh (#{ROUTE_REFRESH}), length: #{msg.size}\n" + "AFI #{IANA.afi(@afi)} (#{@afi}), SAFI #{IANA.safi(@safi)} (#{@safi})"
65
+ end
66
+ end
67
+
68
+ #
69
+ # Carrying ORF Entries in BGP
70
+ #
71
+ # ORF entries are carried in the BGP ROUTE-REFRESH message [BGP-RR].
72
+ #
73
+ # A BGP speaker can distinguish an incoming ROUTE-REFRESH message that
74
+ # carries one or more ORF entries from an incoming plain ROUTE-REFRESH
75
+ # message by using the Message Length field in the BGP message header.
76
+ #
77
+
78
+ class Orf
79
+ def self.factory(s)
80
+ type, len = s.unpack('Cn')
81
+ case type
82
+ when ORF::PREFIX
83
+ Prefix_orf.new(s.slice!(0,len+3).is_packed)
84
+ else
85
+ raise RuntimeError, "orf type #{type} not implemented"
86
+ end
87
+ end
88
+ end
89
+
90
+ #FIXME: Unit-test
91
+ class Orf_route_refresh < Message
92
+
93
+ attr_accessor :orfs
94
+
95
+ def initialize(*args)
96
+ @msg_type=ROUTE_REFRESH
97
+ @orfs=[]
98
+ if args.size==1 and args[0].is_a?(String) and args[0].is_packed?
99
+ parse(args[0])
100
+ elsif args[0].is_a?(self.class)
101
+ parse(args[0].encode, *args[1..-1])
102
+ elsif args.size==1 and args[0].is_a?(Hash)
103
+ self.afi = args[0][:afi] if args[0][:afi]
104
+ self.safi = args[0][:safi] if args[0][:safi]
105
+ else
106
+ @afi, @safi=args
107
+ end
108
+ end
109
+
110
+ def afi_to_i
111
+ @afi
112
+ end
113
+
114
+ def safi_to_i
115
+ @safi
116
+ end
117
+
118
+ def afi
119
+ IANA.afi(@afi)
120
+ end
121
+
122
+ def safi
123
+ IANA.safi(@safi)
124
+ end
125
+
126
+ def afi=(val)
127
+ raise ArgumentError, "invalid argument" unless val.is_a?(Fixnum) and (0..0xffff) === val
128
+ @afi=val
129
+ end
130
+
131
+ def safi=(val)
132
+ raise ArgumentError, "invalid argument" unless val.is_a?(Fixnum) and (0..0xff) === val
133
+ @safi=val
134
+ end
135
+
136
+ def when_to_s
137
+ case @when
138
+ when 1 ; 'defer (1)'
139
+ when 2 ; 'immediate (2)'
140
+ else
141
+ "bogus (#{@when})"
142
+ end
143
+ end
144
+
145
+ def encode
146
+ super([@afi, 0, @safi, @orfs.collect { |o| o.encode }.join].pack('nCCa*'))
147
+ end
148
+
149
+ def parse(s)
150
+ @afi, reserved, @safi, orfs= super(s).unpack('nCCa*')
151
+ while orfs.size>0
152
+ #puts "orfs before factory: #{orfs.unpack('H*')}"
153
+ @orfs << Orf.factory(orfs.is_packed)
154
+ #puts "orfs after factory: #{orfs.unpack('H*')}"
155
+ end
156
+ end
157
+
158
+ def to_hash
159
+ {:afi=> @afi, :safi=> @safi}
160
+ end
161
+
162
+ def to_s
163
+ msg = self.encode
164
+ "ORF Route Refresh (#{ROUTE_REFRESH}), length: #{msg.size}\n" +
165
+ "AFI #{IANA.afi(@afi)} (#{@afi}), SAFI #{IANA.safi(@safi)} (#{@safi}):\n" +
166
+ @orfs.collect { |orf| orf.to_s}.join("\n")
167
+ end
168
+
169
+ def add(*args)
170
+ @orfs ||=[]
171
+ args.each { |arg| @orfs << arg if arg.is_a?(Orf) }
172
+ end
173
+ alias << add
174
+
175
+ def communities
176
+ @communities.collect { |comm| comm.to_s }.join(' ')
177
+ end
178
+
179
+ end
180
+
181
+ end
@@ -0,0 +1,148 @@
1
+
2
+ # UPDATE Message Format
3
+ #
4
+ # UPDATE messages are used to transfer routing information between BGP
5
+ # peers. The information in the UPDATE message can be used to
6
+ # construct a graph that describes the relationships of the various
7
+ # Autonomous Systems. By applying rules to be discussed, routing
8
+ #
9
+ #
10
+ #
11
+ # Rekhter, et al. Standards Track [Page 14]
12
+ #
13
+ # RFC 4271 BGP-4 January 2006
14
+ #
15
+ #
16
+ # information loops and some other anomalies may be detected and
17
+ # removed from inter-AS routing.
18
+ #
19
+ # An UPDATE message is used to advertise feasible routes that share
20
+ # common path Copyright 2008, 2009 to a peer, or to withdraw multiple unfeasible
21
+ # routes from service (see 3.1). An UPDATE message MAY simultaneously
22
+ # advertise a feasible route and withdraw multiple unfeasible routes
23
+ # from service. The UPDATE message always includes the fixed-size BGP
24
+ # header, and also includes the other fields, as shown below (note,
25
+ # some of the shown fields may not be present in every UPDATE message):
26
+ #
27
+ # +-----------------------------------------------------+
28
+ # | Withdrawn Routes Length (2 octets) |
29
+ # +-----------------------------------------------------+
30
+ # | Withdrawn Routes (variable) |
31
+ # +-----------------------------------------------------+
32
+ # | Total Path Attribute Length (2 octets) |
33
+ # +-----------------------------------------------------+
34
+ # | Path Attributes (variable) |
35
+ # +-----------------------------------------------------+
36
+ # | Network Layer Reachability Information (variable) |
37
+ # +-----------------------------------------------------+
38
+ #
39
+
40
+ require 'bgp/messages/message'
41
+ require 'bgp/path_attributes/path_attribute'
42
+
43
+ module BGP
44
+
45
+ class Update < Message
46
+ def as4byte?
47
+ @as4byte ||= false
48
+ end
49
+ def initialize(*args)
50
+ if args[0].is_a?(String) and args[0].is_packed?
51
+ @as4byte=false
52
+ parse(*args)
53
+ elsif args[0].is_a?(self.class)
54
+ parse(args[0].encode, *args[1..-1])
55
+ else
56
+ @msg_type=UPDATE
57
+ set(*args)
58
+ end
59
+ end
60
+
61
+ def set(*args)
62
+ args.each { |arg|
63
+ if arg.is_a?(Withdrawn)
64
+ self.withdrawn=arg
65
+ elsif arg.is_a?(Path_attribute)
66
+ self.path_attribute = arg
67
+ elsif arg.is_a?(Nlri)
68
+ self.nlri = arg
69
+ end
70
+ }
71
+ end
72
+
73
+ def withdrawn=(val)
74
+ @withdrawn=val if val.is_a?(Withdrawn)
75
+ end
76
+
77
+ def nlri=(val)
78
+ @nlri=val if val.is_a?(Nlri)
79
+ end
80
+
81
+ def path_attribute=(val)
82
+ @path_attribute=val if val.is_a?(Path_attribute)
83
+ end
84
+
85
+ def encode(as4byte=false)
86
+ @as4byte=as4byte
87
+ withdrawn, path_attribute, nlri = '', '', ''
88
+ withdrawn = @withdrawn.encode(false) if defined? @withdrawn and @withdrawn
89
+ path_attribute = @path_attribute.encode(as4byte) if defined?(@path_attribute) and @path_attribute
90
+ nlri = @nlri.encode if defined? @nlri and @nlri
91
+ super([withdrawn.size, withdrawn, path_attribute.size, path_attribute, nlri].pack('na*na*a*'))
92
+ end
93
+
94
+ def encode4
95
+ encode(true)
96
+ end
97
+
98
+ attr_reader :path_attribute, :nlri, :withdrawn
99
+
100
+ # CHANGED ME: NO DEFAULT HERE, the factory calling us has to tell what it is giving us.
101
+ def parse(s, as4byte=false)
102
+ @as4byte=as4byte
103
+ update = super(s)
104
+ len = update.slice!(0,2).unpack('n')[0]
105
+ self.withdrawn=Withdrawn.new(update.slice!(0,len).is_packed) if len>0
106
+ len = update.slice!(0,2).unpack('n')[0]
107
+ enc_path_attribute = update.slice!(0,len).is_packed
108
+ self.path_attribute=Path_attribute.new(enc_path_attribute, as4byte) if len>0
109
+ self.nlri = Nlri.new(update) if update.size>0
110
+ end
111
+
112
+ def <<(val)
113
+ if val.is_a?(Attr)
114
+ @path_attribute ||= Path_attribute.new
115
+ @path_attribute << val
116
+ elsif val.is_a?(String)
117
+ begin
118
+ Nlri.new(val)
119
+ @nlri ||=Nlri.new
120
+ @nlri << val
121
+ rescue => e
122
+ end
123
+ elsif val.is_a?(Nlri)
124
+ val.to_s.split.each { |n| self << n }
125
+ end
126
+ end
127
+
128
+ def to_s(as4byte=@as4byte, fmt=:tcpdump)
129
+ msg = encode(as4byte)
130
+ s = []
131
+ s << @withdrawn.to_s if defined?(@withdrawn) and @withdrawn
132
+ s << @path_attribute.to_s(fmt, as4byte) if defined?(@path_attribute) and @path_attribute
133
+ s << @nlri.to_s if defined?(@nlri) and @nlri
134
+ "Update Message (#{UPDATE}), #{as4byte ? "4 bytes AS, " : ''}length: #{msg.size}\n " + s.join("\n") + "\n" + msg.hexlify.join("\n") + "\n"
135
+ end
136
+
137
+ def self.withdrawn(u)
138
+ if u.nlri and u.nlri.size>0
139
+ Update.new(Withdrawn.new(*(u.nlri.nlris.collect { |n| n.to_s})))
140
+ elsif u.path_attribute.has?(Mp_reach)
141
+ pa = Path_attribute.new
142
+ pa << u.path_attribute[ATTR::MP_REACH].new_unreach
143
+ Update.new(pa)
144
+ end
145
+ end
146
+ end
147
+
148
+ end
data/bgp/neighbor.rb CHANGED
@@ -23,6 +23,7 @@
23
23
  require 'socket'
24
24
  require 'thread'
25
25
  require 'observer'
26
+ require 'bgp/io'
26
27
 
27
28
  module BGP
28
29
 
@@ -68,19 +69,22 @@ module BGP
68
69
  # neighbor.capability :route_refresh, 128
69
70
  # neighbor.capability :mbgp, :ipv4, :unicast
70
71
  # neighbor.capability :mbgp, :ipv4, :multicast
72
+
71
73
  def capability(*args)
72
74
  @opt_parms << if args[0].is_a?(Symbol)
73
75
  case args[0]
74
76
  when :route_refresh, :rr
75
- Route_refresh_cap.new(*args[1..-1])
77
+ OPT_PARM::CAP::Route_refresh.new(*args[1..-1])
76
78
  when :mbgp
77
- Mbgp_cap.new(*args[1..-1])
79
+ OPT_PARM::CAP::Mbgp.new(*args[1..-1])
78
80
  when :as4_byte, :as4byte, :as4
79
- As4_cap.new(@my_as)
81
+ OPT_PARM::CAP::As4.new(@my_as)
82
+ when :gr, :graceful_restart
83
+ OPT_PARM::CAP::Graceful_restart.new(*args[1..-1])
80
84
  else
81
85
  raise ArgumentError, "Invalid argument #{args.inspect}", caller
82
86
  end
83
- elsif args[0].is_a?(Capability)
87
+ elsif args[0].is_a?(OPT_PARM::Capability)
84
88
  args[0]
85
89
  else
86
90
  raise ArgumentError, "Invalid argument"
@@ -177,10 +181,7 @@ module BGP
177
181
  io.start
178
182
  @threads.add io.thread
179
183
  }
180
-
181
- def in ; @in.thread ; end
182
- def out ; @out.thread ; end
183
-
184
+
184
185
  send_open :ev_send_open
185
186
 
186
187
  retry_thread if auto_retry == :auto_retry
@@ -206,6 +207,14 @@ module BGP
206
207
  end
207
208
  alias stop disable
208
209
 
210
+ define_method(:in) do
211
+ @in.thread
212
+ end
213
+ define_method(:out) do
214
+ @out.thread
215
+ end
216
+
217
+
209
218
  def send_message(m)
210
219
  raise if m.nil?
211
220
  return unless @out
@@ -231,7 +240,7 @@ module BGP
231
240
  end
232
241
 
233
242
  def init_io
234
- @in = BGP::IO::Input.new(@socket, @holdtime, self)
243
+ @in = BGP::IO::Input.new(@socket, holdtime, self)
235
244
  @out = BGP::IO::Output.new(@socket, @holdtime, self)
236
245
  new_state(:Active, "Open Socket")
237
246
  end
@@ -275,7 +284,7 @@ module BGP
275
284
  else
276
285
  Log.warn "#{self.class}: received open message while in state #{@state}"
277
286
  end
278
- @as4byte = (open.has?(As4_cap) && o.has?(As4_cap))
287
+ @as4byte = (open.has?(OPT_PARM::CAP::As4) && o.has?(OPT_PARM::CAP::As4))
279
288
  end
280
289
 
281
290
  def rcv_keepalive
@@ -306,7 +315,7 @@ module BGP
306
315
  end
307
316
 
308
317
  def to_s
309
- "version: #{@version}, id: #{@id}, as: #{@my_as}, holdtime: #{@holdtime}, peer addr: #{@remote_addr}, local addr: #{@local_addr}"
318
+ "version: #{version}, id: #{@id}, as: #{@my_as}, holdtime: #{@holdtime}, peer addr: #{@remote_addr}, local addr: #{@local_addr}"
310
319
  end
311
320
 
312
321
  end
data/bgp/nlris/inet.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'bgp/nlris/prefix'
2
+
3
+ module BGP
4
+ class Inet_unicast < Prefix
5
+ def safi
6
+ IANA::SAFI::UNICAST_NLRI
7
+ end
8
+ end
9
+
10
+ class Inet_multicast < Prefix
11
+ def safi
12
+ IANA::SAFI::MULTICAST_NLRI
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
@@ -90,5 +90,5 @@ module BGP
90
90
  end
91
91
  end
92
92
 
93
- load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
93
+ load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
94
94
 
@@ -0,0 +1,39 @@
1
+ require 'bgp/nlris/label'
2
+ module BGP
3
+ class Labeled
4
+ def initialize(*args)
5
+ if args.size>0 and args[0].is_a?(String) and args[0].is_packed?
6
+ parse(*args)
7
+ else
8
+ @prefix, *labels = args
9
+ @labels = Label_stack.new(*labels)
10
+ end
11
+ end
12
+ def bit_length
13
+ @labels.bit_length+@prefix.bit_length
14
+ end
15
+ def encode
16
+ [bit_length, @labels.encode, @prefix.encode(false)].pack('Ca*a*')
17
+ end
18
+ def to_s
19
+ "#{@labels} #{@prefix}"
20
+ end
21
+ def afi
22
+ @prefix.afi
23
+ end
24
+ def parse(s, afi=1, safi=1)
25
+ bitlen = s.slice!(0,1).unpack('C')[0]
26
+ @labels = Label_stack.new(s)
27
+ mlen = bitlen - (24*@labels.size)
28
+ prefix = [mlen,s.slice!(0,(mlen+7)/8)].pack("Ca*")
29
+ case safi
30
+ when 128,129
31
+ @prefix = Vpn.new(prefix)
32
+ else
33
+ @prefix = Prefix.new(prefix, afi)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
data/bgp/nlris/nlri.rb ADDED
@@ -0,0 +1,154 @@
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/iana'
26
+
27
+ module BGP
28
+
29
+ class Base_nlri
30
+
31
+ class Nlri_element < IPAddr
32
+ def to_s
33
+ [super, mlen].join('/')
34
+ end
35
+ def encode_next_hop
36
+ hton
37
+ end
38
+ def nbyte
39
+ (mlen+7)/8
40
+ end
41
+ def encode(len_included=true)
42
+ nbyte = (mlen+7)/8
43
+ if len_included
44
+ [mlen, hton].pack("Ca#{nbyte}")
45
+ else
46
+ [hton].pack("a#{nbyte}")
47
+ end
48
+ end
49
+ def parse4(arg)
50
+ s = arg.dup
51
+ s +=([0]*3).pack('C*')
52
+ plen, *nlri = s.unpack('CC4')
53
+ arg.slice!(0,1+(plen+7)/8) # trim arg accordingly
54
+ ipaddr = nlri.collect { |n| n.to_s }.join('.') + "/" + plen .to_s
55
+ end
56
+ def parse6(arg)
57
+ s = arg.dup
58
+ s +=([0]*16).pack('C*')
59
+ plen, *nlri = s.unpack('Cn8')
60
+ arg.slice!(0,1+(plen+7)/8) # trim arg accordingly
61
+ ipaddr = nlri.collect { |n| n.to_s(16) }.join(':') + "/" + plen .to_s
62
+ end
63
+ end
64
+
65
+ class Ip4 < Nlri_element
66
+ def initialize(arg)
67
+ if arg.is_a?(String) and arg.packed?
68
+ super(parse4(arg))
69
+ elsif arg.is_a?(Ip4)
70
+ super(arg.to_s)
71
+ else
72
+ super(arg)
73
+ end
74
+ end
75
+ end
76
+
77
+ class Ip6 < Nlri_element
78
+ def initialize(arg)
79
+ if arg.is_a?(String) and arg.packed?
80
+ super(parse6(arg))
81
+ elsif arg.is_a?(Ip6)
82
+ super(arg.to_s)
83
+ else
84
+ super(arg)
85
+ end
86
+ end
87
+ end
88
+
89
+ attr_reader :nlris
90
+
91
+ def initialize(*args)
92
+ if args[0].is_a?(String) and args[0].is_packed?
93
+ parse(args[0])
94
+ else
95
+ add(*args)
96
+ end
97
+ end
98
+ def add(*args)
99
+ @nlris ||=[]
100
+ args.flatten.each { |arg| @nlris << Ip4.new(arg) }
101
+ end
102
+ alias << add
103
+
104
+ def parse(s)
105
+ @nlris ||=[]
106
+ while s.size>0
107
+ add(s)
108
+ end
109
+ end
110
+
111
+ def encode(len_included=false)
112
+ enc = @nlris.collect { |x| x.encode }.join
113
+ if len_included
114
+ [enc.size].pack('n') + enc
115
+ else
116
+ enc
117
+ end
118
+ end
119
+
120
+ def to_s
121
+ @nlris.join("\n")
122
+ end
123
+
124
+ def size
125
+ @nlris.size
126
+ end
127
+
128
+ end
129
+
130
+ class Nlri < Base_nlri
131
+ def encode
132
+ super
133
+ end
134
+ end
135
+ class Withdrawn < Base_nlri
136
+ def encode(len_included=true)
137
+ super(len_included)
138
+ end
139
+ end
140
+
141
+ class Nlri
142
+ def self.factory(s, afi, safi)
143
+ case safi
144
+ when 1,2
145
+ Prefix.new(s.is_packed, afi)
146
+ when 4,128,129
147
+ Labeled.new(s.is_packed, afi, safi)
148
+ end
149
+ end
150
+ end
151
+
152
+ end
153
+
154
+ load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright 2008, 2009 Jean-Michel Esnault.
2
+ # Copyright 2008, 2009, 2010 Jean-Michel Esnault.
3
3
  # All rights reserved.
4
4
  # See LICENSE.txt for permissions.
5
5
  #
@@ -20,15 +20,13 @@
20
20
  # along with BGP4R. If not, see <http://www.gnu.org/licenses/>.
21
21
  #++
22
22
 
23
- require 'bgp/origin'
24
- require 'bgp/next_hop'
25
- require 'bgp/local_pref'
26
- require 'bgp/multi_exit_disc'
27
- require 'bgp/as_path'
28
- require 'bgp/communities'
29
- require 'bgp/aggregator'
30
- require 'bgp/atomic_aggregate'
31
- require 'bgp/originator_id'
32
- require 'bgp/cluster_list'
33
- require 'bgp/mp_reach'
34
- require 'bgp/extended_communities'
23
+ module BGP
24
+ end
25
+
26
+ %w{ nlri prefix labeled vpn rd }.each do |n|
27
+ BGP.autoload n.capitalize.to_sym,"bgp/nlris/#{n}"
28
+ end
29
+
30
+ BGP.autoload :Inet_unicast, "bgp/nlris/inet"
31
+ BGP.autoload :Inet_multicast, "bgp/nlris/inet"
32
+ BGP.autoload :Withdrawn, "bgp/nlris/nlri"
@@ -0,0 +1,33 @@
1
+ require 'bgp/nlris/nlri'
2
+ module BGP
3
+ class Prefix < Nlri::Nlri_element
4
+ def initialize(*args)
5
+ if args[0].is_a?(String) and args[0].packed?
6
+ afi = args[1] ||=1
7
+ case afi
8
+ when :ip4,1 ; super(parse4(args[0]))
9
+ when :ip6,2 ; super(parse6(args[0]))
10
+ end
11
+ elsif args[0].is_a?(Nlri::Ip4) or args[0].is_a?(Nlri::Ip6) or args[0].is_a?(Prefix)
12
+ super(args[0].to_s)
13
+ else
14
+ super(*args)
15
+ end
16
+ end
17
+ def afi
18
+ if ipv4?
19
+ IANA::AFI::IP
20
+ elsif ipv6?
21
+ IANA::AFI::IP6
22
+ end
23
+ end
24
+ alias bit_length mlen
25
+
26
+ def nexthop
27
+ to_s.split('/')[0]
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
@@ -104,4 +104,4 @@ module BGP
104
104
 
105
105
  end
106
106
  end
107
- load "../test/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
107
+ load "../../test/path_attributes/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0