bgp4r 0.0.11 → 0.0.12
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/common.rb +14 -13
- data/bgp/iana.rb +26 -1
- data/bgp/messages/capability.rb +3 -2
- data/bgp/messages/message.rb +3 -2
- data/bgp/messages/open.rb +2 -1
- data/bgp/messages/update.rb +80 -30
- data/bgp/neighbor/add_path_cap.rb +125 -0
- data/bgp/{neighbor.rb → neighbor/neighbor.rb} +64 -68
- data/bgp/nlris/nlri.rb +289 -15
- data/bgp/nlris/prefix.rb +3 -2
- data/bgp/nlris/vpn.rb +1 -8
- data/bgp/optional_parameters/add_path.rb +160 -0
- data/bgp/optional_parameters/capabilities.rb +1 -0
- data/bgp/optional_parameters/capability.rb +6 -0
- data/bgp/optional_parameters/graceful_restart.rb +6 -6
- data/bgp/optional_parameters/optional_parameter.rb +1 -0
- data/bgp/path_attributes/as_path.rb +1 -1
- data/bgp/path_attributes/attribute.rb +12 -5
- data/bgp/path_attributes/mp_reach.rb +142 -96
- data/bgp/path_attributes/mp_unreach.rb +73 -20
- data/bgp/path_attributes/path_attribute.rb +28 -5
- data/bgp4r.gemspec +21 -6
- data/bgp4r.rb +1 -1
- data/examples/unit-testing/malformed_update.rb +2 -1
- data/examples/unit-testing/test.rb +82 -0
- data/examples/unit-testing/test1.rb +82 -0
- data/examples/unit-testing/test2.rb +44 -0
- data/test/common_test.rb +7 -0
- data/test/helpers/server.rb +20 -0
- data/test/iana_test.rb +43 -0
- data/test/messages/open_test.rb +7 -2
- data/test/messages/update_test.rb +133 -36
- data/test/neighbor/add_path_cap_test.rb +54 -0
- data/test/neighbor/neighbor_test.rb +161 -0
- data/test/nlris/ext_nlri_test.rb +25 -60
- data/test/nlris/nlri_test.rb +93 -115
- data/test/optional_parameters/add_path_test.rb +53 -0
- data/test/optional_parameters/capability_test.rb +10 -0
- data/test/optional_parameters/graceful_restart_test.rb +1 -0
- data/test/path_attributes/mp_reach_test.rb +206 -8
- data/test/path_attributes/mp_unreach_test.rb +113 -5
- data/test/path_attributes/path_attribute_test.rb +34 -2
- metadata +20 -7
- data/test/neighbor_test.rb +0 -62
| @@ -24,21 +24,13 @@ require 'socket' | |
| 24 24 | 
             
            require 'thread'
         | 
| 25 25 | 
             
            require 'observer'
         | 
| 26 26 | 
             
            require 'bgp/io'
         | 
| 27 | 
            +
            require 'bgp/neighbor/add_path_cap'
         | 
| 27 28 |  | 
| 28 29 | 
             
            module BGP
         | 
| 29 30 |  | 
| 30 31 | 
             
              class Neighbor
         | 
| 31 32 | 
             
                include Observable
         | 
| 32 33 |  | 
| 33 | 
            -
                # def self.deprecate(old_method, new_method) 
         | 
| 34 | 
            -
                #   define_method(old_method) do |*args, &block|
         | 
| 35 | 
            -
                #     log_warn "#{old_method}() is deprecated. Use #{new_method}()."
         | 
| 36 | 
            -
                #     __send__(new_method, *args, &block)
         | 
| 37 | 
            -
                #   end 
         | 
| 38 | 
            -
                # end
         | 
| 39 | 
            -
                # 
         | 
| 40 | 
            -
                # deprecate :send_message, :send
         | 
| 41 | 
            -
             | 
| 42 34 | 
             
                def log_info(txt)
         | 
| 43 35 | 
             
                  Log.info "#{self.class} #{txt}"
         | 
| 44 36 | 
             
                end
         | 
| @@ -63,8 +55,8 @@ module BGP | |
| 63 55 | 
             
                  else
         | 
| 64 56 | 
             
                    @version, @my_as, @holdtime, @id, @remote_addr, @local_addr  = args
         | 
| 65 57 | 
             
                  end
         | 
| 66 | 
            -
                  @as4byte=false
         | 
| 67 58 | 
             
                  @state = :Idle
         | 
| 59 | 
            +
                  @session_info=nil
         | 
| 68 60 | 
             
                  @threads=ThreadGroup.new
         | 
| 69 61 | 
             
                  @mutex = Mutex.new
         | 
| 70 62 | 
             
                  @eventQ = Queue.new
         | 
| @@ -77,12 +69,15 @@ module BGP | |
| 77 69 | 
             
                  end
         | 
| 78 70 | 
             
                end
         | 
| 79 71 |  | 
| 72 | 
            +
                # FIXME:
         | 
| 73 | 
            +
                #  neighbor.add_capability 
         | 
| 74 | 
            +
                #  neighbor.remove_capability 
         | 
| 80 75 | 
             
                #  neighbor.capability :as4_byte | :as4 | :as4byte
         | 
| 81 76 | 
             
                #  neighbor.capability :route_refresh, :rr
         | 
| 82 77 | 
             
                #  neighbor.capability :route_refresh, 128
         | 
| 83 78 | 
             
                #  neighbor.capability :mbgp, :ipv4, :unicast
         | 
| 84 79 | 
             
                #  neighbor.capability :mbgp, :ipv4, :multicast
         | 
| 85 | 
            -
             | 
| 80 | 
            +
                
         | 
| 86 81 | 
             
                def capability(*args)
         | 
| 87 82 | 
             
                  @opt_parms << if args[0].is_a?(Symbol)
         | 
| 88 83 | 
             
                    case args[0]
         | 
| @@ -103,6 +98,7 @@ module BGP | |
| 103 98 | 
             
                    raise ArgumentError, "Invalid argument"
         | 
| 104 99 | 
             
                  end
         | 
| 105 100 | 
             
                end
         | 
| 101 | 
            +
                alias :add_cap :capability
         | 
| 106 102 |  | 
| 107 103 | 
             
                def state
         | 
| 108 104 | 
             
                  "#{@state}"
         | 
| @@ -115,7 +111,7 @@ module BGP | |
| 115 111 | 
             
                      Thread.current['name']='restart'
         | 
| 116 112 | 
             
                      loop do
         | 
| 117 113 | 
             
                        enable if @state == :Idle
         | 
| 118 | 
            -
                        sleep( | 
| 114 | 
            +
                        sleep(4)
         | 
| 119 115 | 
             
                      end
         | 
| 120 116 | 
             
                    end
         | 
| 121 117 |  | 
| @@ -132,7 +128,7 @@ module BGP | |
| 132 128 | 
             
                      ev, type, m = eventQ.deq
         | 
| 133 129 | 
             
                      case ev
         | 
| 134 130 | 
             
                      when :ev_msg
         | 
| 135 | 
            -
                        msg = BGP::Message.factory(m, @ | 
| 131 | 
            +
                        msg = BGP::Message.factory(m, @session_info)
         | 
| 136 132 | 
             
                        log_info "Recv#{msg.class.to_s.split('::').last}"
         | 
| 137 133 | 
             
                        log_debug "Recv #{msg}\n"
         | 
| 138 134 | 
             
                        if msg.is_a?(Update)
         | 
| @@ -153,17 +149,17 @@ module BGP | |
| 153 149 | 
             
                        changed and notify_observers(msg)
         | 
| 154 150 | 
             
                      when :ev_conn_reset
         | 
| 155 151 | 
             
                        Log.warn "#{type}"
         | 
| 156 | 
            -
                         | 
| 152 | 
            +
                        stop
         | 
| 157 153 | 
             
                      when :ev_holdtime_expire
         | 
| 158 154 | 
             
                        Log.warn "Holdtime expire: #{type}"
         | 
| 159 | 
            -
                         | 
| 155 | 
            +
                        stop
         | 
| 160 156 | 
             
                      else
         | 
| 161 157 | 
             
                        Log.error "unexpected event #{ev}"
         | 
| 162 158 | 
             
                      end
         | 
| 163 159 | 
             
                    end
         | 
| 164 160 | 
             
                  end
         | 
| 165 161 | 
             
                end
         | 
| 166 | 
            -
             | 
| 162 | 
            +
                
         | 
| 167 163 | 
             
                def clean
         | 
| 168 164 | 
             
                  @threads.list.each { |x| 
         | 
| 169 165 | 
             
                    x.exit; x.join
         | 
| @@ -183,42 +179,42 @@ module BGP | |
| 183 179 | 
             
                  @holdtime ||= 180
         | 
| 184 180 | 
             
                end
         | 
| 185 181 |  | 
| 186 | 
            -
                def  | 
| 182 | 
            +
                def start_session(session)
         | 
| 183 | 
            +
                  @socket=session
         | 
| 184 | 
            +
                  return unless  @state == :Idle
         | 
| 185 | 
            +
                  init_io
         | 
| 186 | 
            +
                  send_open :ev_send_open
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
                
         | 
| 189 | 
            +
                def start(arg={})
         | 
| 190 | 
            +
                  options = {:port=> 179, :auto_retry=> false, :no_blocking=>false, :waitfor=> :Established}.merge(arg)
         | 
| 187 191 | 
             
                  return if @state == :Established
         | 
| 188 | 
            -
                   | 
| 189 | 
            -
                  
         | 
| 190 | 
            -
             | 
| 192 | 
            +
                  stop unless @state == :Idle
         | 
| 193 | 
            +
                  if options[:session]
         | 
| 194 | 
            +
                    @socket = session
         | 
| 195 | 
            +
                  else
         | 
| 196 | 
            +
                    @socket = TCPSocket.new(@remote_addr, options[:port])
         | 
| 197 | 
            +
                  end
         | 
| 191 198 | 
             
                  init_io
         | 
| 192 | 
            -
                        
         | 
| 193 | 
            -
                  [@in, @out].each { |io| 
         | 
| 194 | 
            -
                    io.start 
         | 
| 195 | 
            -
                    @threads.add io.thread
         | 
| 196 | 
            -
                  }
         | 
| 197 | 
            -
                        
         | 
| 198 199 | 
             
                  send_open :ev_send_open
         | 
| 199 | 
            -
                  
         | 
| 200 | 
            -
                   | 
| 201 | 
            -
                  
         | 
| 202 | 
            -
                  if wait == :wait
         | 
| 200 | 
            +
                  retry_thread if options[:auto_retry] == true
         | 
| 201 | 
            +
                  unless options[:no_blocking] == true
         | 
| 203 202 | 
             
                    loop do
         | 
| 204 203 | 
             
                      sleep(0.3)
         | 
| 205 | 
            -
                      break if @state == : | 
| 204 | 
            +
                      break if @state == options[:waitfor]
         | 
| 206 205 | 
             
                    end
         | 
| 207 206 | 
             
                    log_info "#{self} started"
         | 
| 208 207 | 
             
                  end
         | 
| 209 | 
            -
                  
         | 
| 210 208 | 
             
                rescue => e
         | 
| 211 209 | 
             
                  Log.error "#{e}"
         | 
| 212 | 
            -
                   | 
| 210 | 
            +
                  stop
         | 
| 213 211 | 
             
                end
         | 
| 214 | 
            -
                alias start enable
         | 
| 215 212 |  | 
| 216 | 
            -
                def  | 
| 213 | 
            +
                def stop
         | 
| 217 214 | 
             
                  @socket.close  if defined?(@socket) and not @socket.closed?
         | 
| 218 215 | 
             
                  clean
         | 
| 219 216 | 
             
                  new_state :Idle, "Disable"
         | 
| 220 217 | 
             
                end
         | 
| 221 | 
            -
                alias stop disable
         | 
| 222 218 |  | 
| 223 219 | 
             
                define_method(:in) do
         | 
| 224 220 | 
             
                  @in.thread
         | 
| @@ -227,7 +223,11 @@ module BGP | |
| 227 223 | 
             
                  @out.thread
         | 
| 228 224 | 
             
                end
         | 
| 229 225 |  | 
| 230 | 
            -
                attr_reader :as4byte
         | 
| 226 | 
            +
                attr_reader :as4byte, :session_info
         | 
| 227 | 
            +
                
         | 
| 228 | 
            +
                def as4byte?
         | 
| 229 | 
            +
                  @session_info.as4byte?
         | 
| 230 | 
            +
                end
         | 
| 231 231 |  | 
| 232 232 | 
             
                def send_message(m)
         | 
| 233 233 | 
             
                  raise if m.nil?
         | 
| @@ -236,30 +236,23 @@ module BGP | |
| 236 236 | 
             
                    log_info "Send#{m.class.to_s.split('::')[-1]}"
         | 
| 237 237 | 
             
                    log_debug "Send #{m.is_a?(Update) ? m.to_s : m }\n"
         | 
| 238 238 | 
             
                  end
         | 
| 239 | 
            -
                  #FIXME: enqueue [m, as4byte]
         | 
| 240 239 | 
             
                  if m.is_a?(Update)
         | 
| 241 | 
            -
             | 
| 240 | 
            +
                     send_update m
         | 
| 242 241 | 
             
                  else
         | 
| 243 242 | 
             
                    @out.enq m
         | 
| 244 243 | 
             
                  end
         | 
| 245 244 | 
             
                end
         | 
| 246 | 
            -
             | 
| 247 | 
            -
                def init_socket
         | 
| 248 | 
            -
                  @socket = Socket.new(Socket::PF_INET, Socket::SOCK_STREAM, Socket::IPPROTO_TCP)
         | 
| 249 | 
            -
                  remote = Socket.pack_sockaddr_in(179, @remote_addr) 
         | 
| 250 | 
            -
                  local = Socket.pack_sockaddr_in(0, @local_addr) unless @local_addr.nil?
         | 
| 251 | 
            -
                  remote_sock_addr = Socket.pack_sockaddr_in(179, @remote_addr) 
         | 
| 252 | 
            -
                  local_sock_addr = Socket.pack_sockaddr_in(0, @local_addr) unless @local_addr.nil? 
         | 
| 253 | 
            -
                  @socket.bind(local_sock_addr) unless @local_addr.nil?
         | 
| 254 | 
            -
                  @socket.connect(remote_sock_addr)
         | 
| 255 | 
            -
                end
         | 
| 256 | 
            -
                  
         | 
| 245 | 
            +
                
         | 
| 257 246 | 
             
                def init_io
         | 
| 258 247 | 
             
                  @in = BGP::IO::Input.new(@socket, holdtime, self)
         | 
| 259 248 | 
             
                  @out = BGP::IO::Output.new(@socket, @holdtime, self)
         | 
| 260 249 | 
             
                  new_state(:Active, "Open Socket")
         | 
| 250 | 
            +
                  [@in, @out].each { |io| 
         | 
| 251 | 
            +
                    io.start 
         | 
| 252 | 
            +
                    @threads.add io.thread
         | 
| 253 | 
            +
                  }
         | 
| 261 254 | 
             
                end
         | 
| 262 | 
            -
             | 
| 255 | 
            +
                
         | 
| 263 256 | 
             
                def update(*args)
         | 
| 264 257 | 
             
                  @eventQ.enq(args)
         | 
| 265 258 | 
             
                end
         | 
| @@ -268,7 +261,11 @@ module BGP | |
| 268 261 | 
             
                  log_info "#{txt} old state #{@state} new state #{state}"
         | 
| 269 262 | 
             
                  @state = state
         | 
| 270 263 | 
             
                end
         | 
| 271 | 
            -
             | 
| 264 | 
            +
                
         | 
| 265 | 
            +
                def send_update(u)
         | 
| 266 | 
            +
                  @out.enq u.encode(@session_info)
         | 
| 267 | 
            +
                end
         | 
| 268 | 
            +
                
         | 
| 272 269 | 
             
                def send_open(ev)
         | 
| 273 270 | 
             
                  case @state
         | 
| 274 271 | 
             
                  when :OpenRecv
         | 
| @@ -277,18 +274,17 @@ module BGP | |
| 277 274 | 
             
                    send_message open  ; new_state :OpenSent, ev
         | 
| 278 275 | 
             
                  else
         | 
| 279 276 | 
             
                    Log.warn "#{self.class}: attempt to send OPEN msg while in #{@state}"
         | 
| 280 | 
            -
                  end | 
| 277 | 
            +
                  end
         | 
| 281 278 | 
             
                end
         | 
| 282 279 |  | 
| 283 | 
            -
                def rcv_open( | 
| 284 | 
            -
                  @ | 
| 285 | 
            -
                   | 
| 286 | 
            -
                  @ | 
| 287 | 
            -
             | 
| 288 | 
            -
                   | 
| 289 | 
            -
             | 
| 290 | 
            -
                   | 
| 291 | 
            -
             | 
| 280 | 
            +
                def rcv_open(peer_open)
         | 
| 281 | 
            +
                  @session_info = Neighbor::Capabilities.new open, peer_open
         | 
| 282 | 
            +
                  
         | 
| 283 | 
            +
                  @rmt_version  = peer_open.version
         | 
| 284 | 
            +
                  @rmt_as       = peer_open.local_as
         | 
| 285 | 
            +
                  @rmt_bgp_id   = peer_open.bgp_id
         | 
| 286 | 
            +
                  @out.holdtime = @in.holdtime = peer_open.holdtime if @holdtime > peer_open.holdtime
         | 
| 287 | 
            +
                  
         | 
| 292 288 | 
             
                  case @state
         | 
| 293 289 | 
             
                  when :OpenSent
         | 
| 294 290 | 
             
                    send_message(BGP::Message.keepalive)
         | 
| @@ -299,7 +295,7 @@ module BGP | |
| 299 295 | 
             
                  else
         | 
| 300 296 | 
             
                    Log.warn "#{self.class}: received open message while in state #{@state}"
         | 
| 301 297 | 
             
                  end
         | 
| 302 | 
            -
                   | 
| 298 | 
            +
                  
         | 
| 303 299 | 
             
                end
         | 
| 304 300 |  | 
| 305 301 | 
             
                def rcv_keepalive
         | 
| @@ -317,25 +313,25 @@ module BGP | |
| 317 313 | 
             
                    @threads.add(@keepalive_thread)
         | 
| 318 314 | 
             
                  end
         | 
| 319 315 | 
             
                end
         | 
| 320 | 
            -
             | 
| 316 | 
            +
                
         | 
| 321 317 | 
             
                def rcv_notification(m)
         | 
| 322 318 | 
             
                  log_info "#{m}"
         | 
| 323 319 | 
             
                  changed and notify_observers(m)
         | 
| 324 | 
            -
                   | 
| 320 | 
            +
                  stop
         | 
| 325 321 | 
             
                end
         | 
| 326 322 |  | 
| 327 323 | 
             
                def rcv_route_refresh(m)
         | 
| 328 324 | 
             
                end
         | 
| 329 | 
            -
             | 
| 325 | 
            +
                
         | 
| 330 326 | 
             
                def rcv_update(m)
         | 
| 331 327 | 
             
                end
         | 
| 332 328 |  | 
| 333 329 | 
             
                def to_s
         | 
| 334 330 | 
             
                  "version: #{version}, id: #{@id}, as: #{@my_as}, holdtime: #{@holdtime}, peer addr: #{@remote_addr}, local addr: #{@local_addr}"
         | 
| 335 331 | 
             
                end
         | 
| 336 | 
            -
             | 
| 332 | 
            +
                
         | 
| 337 333 | 
             
              end
         | 
| 338 334 |  | 
| 339 335 | 
             
            end
         | 
| 340 336 |  | 
| 341 | 
            -
            load " | 
| 337 | 
            +
            load "../../test/neighbor/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
         | 
    
        data/bgp/nlris/nlri.rb
    CHANGED
    
    | @@ -29,6 +29,7 @@ module BGP | |
| 29 29 | 
             
              class Base_nlri
         | 
| 30 30 |  | 
| 31 31 | 
             
                class Nlri_element < IPAddr
         | 
| 32 | 
            +
             | 
| 32 33 | 
             
                  def to_s
         | 
| 33 34 | 
             
                    [super, mlen].join('/')
         | 
| 34 35 | 
             
                  end
         | 
| @@ -36,7 +37,7 @@ module BGP | |
| 36 37 | 
             
                    hton
         | 
| 37 38 | 
             
                  end
         | 
| 38 39 | 
             
                  def nbyte
         | 
| 39 | 
            -
             | 
| 40 | 
            +
                    (mlen+7)/8
         | 
| 40 41 | 
             
                  end
         | 
| 41 42 | 
             
                  def encode(len_included=true)
         | 
| 42 43 | 
             
                    nbyte = (mlen+7)/8
         | 
| @@ -46,13 +47,14 @@ module BGP | |
| 46 47 | 
             
                      [hton].pack("a#{nbyte}")
         | 
| 47 48 | 
             
                    end
         | 
| 48 49 | 
             
                  end
         | 
| 49 | 
            -
                  def  | 
| 50 | 
            +
                  def parse(arg)
         | 
| 50 51 | 
             
                    s = arg.dup
         | 
| 51 52 | 
             
                    s +=([0]*3).pack('C*')
         | 
| 52 53 | 
             
                    plen, *nlri = s.unpack('CC4')
         | 
| 53 54 | 
             
                    arg.slice!(0,1+(plen+7)/8) # trim arg accordingly
         | 
| 54 55 | 
             
                    ipaddr = nlri.collect { |n| n.to_s }.join('.') + "/" + plen .to_s
         | 
| 55 56 | 
             
                  end
         | 
| 57 | 
            +
                  alias :parse4 :parse
         | 
| 56 58 | 
             
                  def parse6(arg)
         | 
| 57 59 | 
             
                    s = arg.dup
         | 
| 58 60 | 
             
                    s +=([0]*16).pack('C*')
         | 
| @@ -71,6 +73,10 @@ module BGP | |
| 71 73 | 
             
                    else
         | 
| 72 74 | 
             
                      super(arg)
         | 
| 73 75 | 
             
                    end
         | 
| 76 | 
            +
                  rescue => e
         | 
| 77 | 
            +
                    p e
         | 
| 78 | 
            +
                    p arg
         | 
| 79 | 
            +
                    raise
         | 
| 74 80 | 
             
                  end
         | 
| 75 81 | 
             
                end
         | 
| 76 82 |  | 
| @@ -86,18 +92,90 @@ module BGP | |
| 86 92 | 
             
                  end
         | 
| 87 93 | 
             
                end
         | 
| 88 94 |  | 
| 95 | 
            +
                class Ext_Nlri_element < Nlri_element
         | 
| 96 | 
            +
                  def initialize(*args)
         | 
| 97 | 
            +
                    if args.size>1
         | 
| 98 | 
            +
                      @path_id = args.shift
         | 
| 99 | 
            +
                      super
         | 
| 100 | 
            +
                    elsif args.size==1 and args[0].is_a?(String)
         | 
| 101 | 
            +
                      super parse(*args)
         | 
| 102 | 
            +
                    elsif args.size==1 and args[0].is_a?(Hash)
         | 
| 103 | 
            +
                      @path_id=args[0][:path_id]
         | 
| 104 | 
            +
                      super args[0][:nlri_element]
         | 
| 105 | 
            +
                    else
         | 
| 106 | 
            +
                      raise
         | 
| 107 | 
            +
                    end
         | 
| 108 | 
            +
                  rescue => e
         | 
| 109 | 
            +
                    p e
         | 
| 110 | 
            +
                    p args
         | 
| 111 | 
            +
                    raise
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
                  attr_reader :path_id
         | 
| 114 | 
            +
                  def encode
         | 
| 115 | 
            +
                    [path_id, super].pack('Na*')
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
                  def to_s
         | 
| 118 | 
            +
                    "ID: #{path_id}, #{super}"
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                  def parse(s)
         | 
| 121 | 
            +
                    @path_id = s.slice!(0,4).unpack('N')[0]
         | 
| 122 | 
            +
                    super s
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 89 126 | 
             
                attr_reader :nlris
         | 
| 127 | 
            +
                
         | 
| 128 | 
            +
                class << self
         | 
| 129 | 
            +
                  def new_ntop(s, extended=false)
         | 
| 130 | 
            +
                    if extended
         | 
| 131 | 
            +
                      nlri = new
         | 
| 132 | 
            +
                      while s.size>0
         | 
| 133 | 
            +
                        nlri.add Base_nlri::Ext_Nlri_element.new(s)
         | 
| 134 | 
            +
                      end
         | 
| 135 | 
            +
                      nlri
         | 
| 136 | 
            +
                    else
         | 
| 137 | 
            +
                      new(s.is_packed)
         | 
| 138 | 
            +
                    end
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                end
         | 
| 90 141 |  | 
| 91 142 | 
             
                def initialize(*args)
         | 
| 92 143 | 
             
                  if args[0].is_a?(String) and args[0].is_packed?
         | 
| 93 | 
            -
                    parse(args | 
| 144 | 
            +
                    parse(*args)
         | 
| 94 145 | 
             
                  else
         | 
| 95 146 | 
             
                    add(*args)
         | 
| 96 147 | 
             
                  end
         | 
| 97 148 | 
             
                end
         | 
| 98 149 | 
             
                def add(*args)
         | 
| 99 150 | 
             
                  @nlris ||=[]
         | 
| 100 | 
            -
                  args. | 
| 151 | 
            +
                  args.each { |arg|
         | 
| 152 | 
            +
                    case arg
         | 
| 153 | 
            +
                    when Hash
         | 
| 154 | 
            +
                      if arg.has_key? :path_id
         | 
| 155 | 
            +
                        @nlris << Ext_Nlri_element.new(arg)
         | 
| 156 | 
            +
                      else
         | 
| 157 | 
            +
                        raise
         | 
| 158 | 
            +
                      end
         | 
| 159 | 
            +
                    when String
         | 
| 160 | 
            +
                      # p "JME: IN ADD/ STRING:"
         | 
| 161 | 
            +
                      # p arg
         | 
| 162 | 
            +
                      # p arg.is_packed?
         | 
| 163 | 
            +
                      # p "---"
         | 
| 164 | 
            +
                      o = Ip4.new(arg)
         | 
| 165 | 
            +
                      # p o
         | 
| 166 | 
            +
                      @nlris << o
         | 
| 167 | 
            +
                    when Array
         | 
| 168 | 
            +
                      if arg[0].is_a?(Integer)
         | 
| 169 | 
            +
                        @nlris << Ext_Nlri_element.new(*arg)
         | 
| 170 | 
            +
                      else
         | 
| 171 | 
            +
                        raise
         | 
| 172 | 
            +
                      end
         | 
| 173 | 
            +
                    when Ext_Nlri_element, Ip4
         | 
| 174 | 
            +
                      @nlris << arg
         | 
| 175 | 
            +
                    else
         | 
| 176 | 
            +
                      raise ArgumentError, "Invalid argument #{arg.class} #{arg.inspect}"
         | 
| 177 | 
            +
                    end
         | 
| 178 | 
            +
                  }
         | 
| 101 179 | 
             
                end
         | 
| 102 180 | 
             
                alias << add
         | 
| 103 181 |  | 
| @@ -117,10 +195,10 @@ module BGP | |
| 117 195 | 
             
                  end
         | 
| 118 196 | 
             
                end
         | 
| 119 197 |  | 
| 120 | 
            -
                def to_s
         | 
| 121 | 
            -
                  @nlris.join("\n")
         | 
| 198 | 
            +
                def to_s(indent=0)
         | 
| 199 | 
            +
                  @nlris.join("\n#{([' ']*indent).join}")
         | 
| 122 200 | 
             
                end
         | 
| 123 | 
            -
             | 
| 201 | 
            +
             | 
| 124 202 | 
             
                def size
         | 
| 125 203 | 
             
                  @nlris.size
         | 
| 126 204 | 
             
                end
         | 
| @@ -132,23 +210,219 @@ module BGP | |
| 132 210 | 
             
                  super
         | 
| 133 211 | 
             
                end
         | 
| 134 212 | 
             
              end
         | 
| 213 | 
            +
             | 
| 135 214 | 
             
              class Withdrawn < Base_nlri
         | 
| 136 | 
            -
                 | 
| 137 | 
            -
                   | 
| 215 | 
            +
                class << self
         | 
| 216 | 
            +
                  def new_top(*args)
         | 
| 217 | 
            +
                    super
         | 
| 218 | 
            +
                  end
         | 
| 219 | 
            +
                end
         | 
| 220 | 
            +
                class << self
         | 
| 221 | 
            +
                  def new_ntop(s, extended=false)
         | 
| 222 | 
            +
                    if extended
         | 
| 223 | 
            +
                      nlri = new
         | 
| 224 | 
            +
                      while s.size>0
         | 
| 225 | 
            +
                        nlri.add Base_nlri::Ext_Nlri_element.new(s)
         | 
| 226 | 
            +
                      end
         | 
| 227 | 
            +
                      nlri
         | 
| 228 | 
            +
                    else
         | 
| 229 | 
            +
                      new(s.is_packed)
         | 
| 230 | 
            +
                    end
         | 
| 231 | 
            +
                  end
         | 
| 232 | 
            +
                end
         | 
| 233 | 
            +
                def encode
         | 
| 234 | 
            +
                  super
         | 
| 138 235 | 
             
                end
         | 
| 139 236 | 
             
              end
         | 
| 140 237 |  | 
| 141 238 | 
             
              class Nlri
         | 
| 142 | 
            -
                def self.factory(s, afi, safi)
         | 
| 143 | 
            -
                   | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
                     | 
| 239 | 
            +
                def self.factory(s, afi, safi, extended=false)
         | 
| 240 | 
            +
                  if afi== 1 and safi==1
         | 
| 241 | 
            +
                    Nlri.new_ntop(s.is_packed, extended)
         | 
| 242 | 
            +
                  else
         | 
| 243 | 
            +
                    case safi
         | 
| 244 | 
            +
                    when 1,2
         | 
| 245 | 
            +
                      Prefix.new(s.is_packed, afi)
         | 
| 246 | 
            +
                    when 4,128,129
         | 
| 247 | 
            +
                      Labeled.new(s.is_packed, afi, safi)
         | 
| 248 | 
            +
                    else
         | 
| 249 | 
            +
                      raise RuntimeError, "Afi #{afi} Safi #{safi} not supported!"
         | 
| 250 | 
            +
                    end
         | 
| 148 251 | 
             
                  end
         | 
| 149 252 | 
             
                end
         | 
| 150 253 | 
             
              end
         | 
| 151 254 |  | 
| 255 | 
            +
              class Ext_Nlri
         | 
| 256 | 
            +
                def self.factory(s, afi, safi)
         | 
| 257 | 
            +
                  new_ntop s, afi, safi
         | 
| 258 | 
            +
                end
         | 
| 259 | 
            +
                def self.new_ntop(s, afi=1, safi=1)
         | 
| 260 | 
            +
                  path_id = s.slice!(0,4).unpack('N')[0]
         | 
| 261 | 
            +
                  nlri = Nlri.factory(s, afi, safi)
         | 
| 262 | 
            +
                  new path_id, nlri
         | 
| 263 | 
            +
                end
         | 
| 264 | 
            +
                attr :path_id, :nlri
         | 
| 265 | 
            +
                def initialize(path_id, nlri)
         | 
| 266 | 
            +
                  @path_id=path_id
         | 
| 267 | 
            +
                  @nlri = nlri
         | 
| 268 | 
            +
                end
         | 
| 269 | 
            +
                def afi
         | 
| 270 | 
            +
                  @nlri.afi
         | 
| 271 | 
            +
                end
         | 
| 272 | 
            +
                def to_s
         | 
| 273 | 
            +
                  s = []
         | 
| 274 | 
            +
                  s << "ID=#{@path_id}"
         | 
| 275 | 
            +
                  s << @nlri.to_s
         | 
| 276 | 
            +
                  s.join(", ")
         | 
| 277 | 
            +
                end
         | 
| 278 | 
            +
                def encode
         | 
| 279 | 
            +
                  [@path_id, @nlri.encode].pack('Na*')
         | 
| 280 | 
            +
                end
         | 
| 281 | 
            +
              end
         | 
| 282 | 
            +
             | 
| 152 283 | 
             
            end
         | 
| 153 284 |  | 
| 154 285 | 
             
            load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
         | 
| 286 | 
            +
             | 
| 287 | 
            +
             | 
| 288 | 
            +
            __END__
         | 
| 289 | 
            +
             | 
| 290 | 
            +
             | 
| 291 | 
            +
            Nlri is a collection of Nlri_elements or a collection of Path_nlri_elements
         | 
| 292 | 
            +
             | 
| 293 | 
            +
             | 
| 294 | 
            +
            Path_nlri_element
         | 
| 295 | 
            +
             | 
| 296 | 
            +
            - path_id
         | 
| 297 | 
            +
            - Nlri_element
         | 
| 298 | 
            +
             | 
| 299 | 
            +
             | 
| 300 | 
            +
             | 
| 301 | 
            +
            3. Extended NLRI Encodings
         | 
| 302 | 
            +
             | 
| 303 | 
            +
            In order to carry the Path Identifier in an UPDATE message, the
         | 
| 304 | 
            +
            existing NLRI encodings are extended by prepending the Path
         | 
| 305 | 
            +
            Identifier field, which is of four-octets.
         | 
| 306 | 
            +
             | 
| 307 | 
            +
            For example, the NLRI encodings specified in [RFC4271, RFC4760] are
         | 
| 308 | 
            +
            extended as the following:
         | 
| 309 | 
            +
             | 
| 310 | 
            +
             | 
| 311 | 
            +
            +--------------------------------+
         | 
| 312 | 
            +
            | Path Identifier (4 octets)     |
         | 
| 313 | 
            +
            +--------------------------------+
         | 
| 314 | 
            +
            | Length (1 octet)               |
         | 
| 315 | 
            +
            +--------------------------------+
         | 
| 316 | 
            +
            | Prefix (variable)              |
         | 
| 317 | 
            +
            +--------------------------------+
         | 
| 318 | 
            +
             | 
| 319 | 
            +
             | 
| 320 | 
            +
            and the NLRI encoding specified in [RFC3107] is extended as the
         | 
| 321 | 
            +
            following:
         | 
| 322 | 
            +
             | 
| 323 | 
            +
             | 
| 324 | 
            +
             | 
| 325 | 
            +
             | 
| 326 | 
            +
             | 
| 327 | 
            +
            Walton, et al        Expiration Date February 2011              [Page 3]
         | 
| 328 | 
            +
             | 
| 329 | 
            +
             | 
| 330 | 
            +
             | 
| 331 | 
            +
             | 
| 332 | 
            +
             | 
| 333 | 
            +
            INTERNET DRAFT      draft-ietf-idr-add-paths-04.txt          August 2010
         | 
| 334 | 
            +
             | 
| 335 | 
            +
             | 
| 336 | 
            +
            +--------------------------------+
         | 
| 337 | 
            +
            | Path Identifier (4 octets)     |
         | 
| 338 | 
            +
            +--------------------------------+
         | 
| 339 | 
            +
            | Length (1 octet)               |
         | 
| 340 | 
            +
            +--------------------------------+
         | 
| 341 | 
            +
            | Label (3 octets)               |
         | 
| 342 | 
            +
            +--------------------------------+
         | 
| 343 | 
            +
            | ...                            |
         | 
| 344 | 
            +
            +--------------------------------+
         | 
| 345 | 
            +
            | Prefix (variable)              |
         | 
| 346 | 
            +
            +--------------------------------+
         | 
| 347 | 
            +
             | 
| 348 | 
            +
             | 
| 349 | 
            +
            The usage of the extended NLRI encodings is specified in the
         | 
| 350 | 
            +
            Operation section.
         | 
| 351 | 
            +
             | 
| 352 | 
            +
             | 
| 353 | 
            +
             | 
| 354 | 
            +
            =======
         | 
| 355 | 
            +
             | 
| 356 | 
            +
            RFC 3107          Carrying Label Information in BGP-4           May 2001
         | 
| 357 | 
            +
             | 
| 358 | 
            +
             | 
| 359 | 
            +
            3. Carrying Label Mapping Information
         | 
| 360 | 
            +
             | 
| 361 | 
            +
            Label mapping information is carried as part of the Network Layer
         | 
| 362 | 
            +
            Reachability Information (NLRI) in the Multiprotocol Extensions
         | 
| 363 | 
            +
            attributes.  The AFI indicates, as usual, the address family of the
         | 
| 364 | 
            +
            associated route.  The fact that the NLRI contains a label is
         | 
| 365 | 
            +
            indicated by using SAFI value 4.
         | 
| 366 | 
            +
             | 
| 367 | 
            +
            The Network Layer Reachability information is encoded as one or more
         | 
| 368 | 
            +
            triples of the form <length, label, prefix>, whose fields are
         | 
| 369 | 
            +
            described below:
         | 
| 370 | 
            +
             | 
| 371 | 
            +
            +---------------------------+
         | 
| 372 | 
            +
            |   Length (1 octet)        |
         | 
| 373 | 
            +
            +---------------------------+
         | 
| 374 | 
            +
            |   Label (3 octets)        |
         | 
| 375 | 
            +
            +---------------------------+
         | 
| 376 | 
            +
            .............................
         | 
| 377 | 
            +
            +---------------------------+
         | 
| 378 | 
            +
            |   Prefix (variable)       |
         | 
| 379 | 
            +
            +---------------------------+
         | 
| 380 | 
            +
             | 
| 381 | 
            +
            The use and the meaning of these fields are as follows:
         | 
| 382 | 
            +
             | 
| 383 | 
            +
            a) Length:
         | 
| 384 | 
            +
             | 
| 385 | 
            +
            The Length field indicates the length in bits of the address
         | 
| 386 | 
            +
            prefix plus the label(s).
         | 
| 387 | 
            +
             | 
| 388 | 
            +
            b) Label:
         | 
| 389 | 
            +
             | 
| 390 | 
            +
            The Label field carries one or more labels (that corresponds to
         | 
| 391 | 
            +
            the stack of labels [MPLS-ENCAPS]).  Each label is encoded as 3
         | 
| 392 | 
            +
            octets, where the high-order 20 bits contain the label value,
         | 
| 393 | 
            +
            and the low order bit contains "Bottom of Stack" (as defined in
         | 
| 394 | 
            +
            [MPLS-ENCAPS]).
         | 
| 395 | 
            +
             | 
| 396 | 
            +
            c) Prefix:
         | 
| 397 | 
            +
             | 
| 398 | 
            +
            The Prefix field contains address prefixes followed by enough
         | 
| 399 | 
            +
            trailing bits to make the end of the field fall on an octet
         | 
| 400 | 
            +
            boundary.  Note that the value of trailing bits is irrelevant.
         | 
| 401 | 
            +
             | 
| 402 | 
            +
             | 
| 403 | 
            +
             | 
| 404 | 
            +
            Rekhter & Rosen             Standards Track                     [Page 3]
         | 
| 405 | 
            +
             | 
| 406 | 
            +
            RFC 3107          Carrying Label Information in BGP-4           May 2001
         | 
| 407 | 
            +
             | 
| 408 | 
            +
             | 
| 409 | 
            +
            The label(s) specified for a particular route (and associated with
         | 
| 410 | 
            +
            its address prefix) must be assigned by the LSR which is identified
         | 
| 411 | 
            +
            by the value of the Next Hop attribute of the route.
         | 
| 412 | 
            +
             | 
| 413 | 
            +
            When a BGP speaker redistributes a route, the label(s) assigned to
         | 
| 414 | 
            +
            that route must not be changed (except by omission), unless the
         | 
| 415 | 
            +
            speaker changes the value of the Next Hop attribute of the route.
         | 
| 416 | 
            +
             | 
| 417 | 
            +
            A BGP speaker can withdraw a previously advertised route (as well as
         | 
| 418 | 
            +
            the binding between this route and a label) by either (a) advertising
         | 
| 419 | 
            +
            a new route (and a label) with the same NLRI as the previously
         | 
| 420 | 
            +
            advertised route, or (b) listing the NLRI of the previously
         | 
| 421 | 
            +
            advertised route in the Withdrawn Routes field of an Update message.
         | 
| 422 | 
            +
            The label information carried (as part of NLRI) in the Withdrawn
         | 
| 423 | 
            +
            Routes field should be set to 0x800000.  (Of course, terminating the
         | 
| 424 | 
            +
            BGP session also withdraws all the previously advertised routes.)
         | 
| 425 | 
            +
             | 
| 426 | 
            +
             | 
| 427 | 
            +
             | 
| 428 | 
            +
             | 
    
        data/bgp/nlris/prefix.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            require 'bgp/nlris/nlri'
         | 
| 2 2 | 
             
            module BGP
         | 
| 3 | 
            -
              class Prefix <  | 
| 3 | 
            +
              class Prefix < Base_nlri::Nlri_element
         | 
| 4 4 | 
             
                def initialize(*args)
         | 
| 5 5 | 
             
                  if args[0].is_a?(String) and args[0].packed?
         | 
| 6 6 | 
             
                    afi = args[1] ||=1
         | 
| @@ -30,4 +30,5 @@ module BGP | |
| 30 30 | 
             
              end
         | 
| 31 31 | 
             
            end
         | 
| 32 32 |  | 
| 33 | 
            -
             | 
| 33 | 
            +
            # FIXME:
         | 
| 34 | 
            +
            # load "../../test/nlris/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
         | 
    
        data/bgp/nlris/vpn.rb
    CHANGED
    
    | @@ -52,17 +52,10 @@ module BGP | |
| 52 52 | 
             
                  @prefix.ipv6?
         | 
| 53 53 | 
             
                end
         | 
| 54 54 | 
             
                def parse(s, afi=1)
         | 
| 55 | 
            -
                  # p "-----------"
         | 
| 56 | 
            -
                  # p s.unpack('H*')
         | 
| 57 | 
            -
                  # p afi
         | 
| 58 55 | 
             
                  nbits = s.slice!(0,1).unpack('C')[0]
         | 
| 59 56 | 
             
                  rd,vpn = s.slice!(0,(7+nbits)/8).unpack("a8a*")
         | 
| 60 57 | 
             
                  @rd = Rd.new(rd.is_packed)
         | 
| 61 | 
            -
                   | 
| 62 | 
            -
                  # p nbits
         | 
| 63 | 
            -
                  # p vpn.unpack('H*')
         | 
| 64 | 
            -
                  raise if nbits-64==0
         | 
| 65 | 
            -
                  @prefix= Prefix.new([nbits-64,vpn].pack('Ca*'), afi) if nbits-64>0
         | 
| 58 | 
            +
                  @prefix= Prefix.new([nbits-64,vpn].pack('Ca*'), afi)
         | 
| 66 59 | 
             
                end
         | 
| 67 60 | 
             
                def nexthop
         | 
| 68 61 | 
             
                  @prefix.nexthop
         |