class Trema::Controller
The base class of Trema
controller. Subclass and override handlers to implement a custom OpenFlow controller.
rubocop:disable ClassLength
Constants
- DEFAULT_TCP_PORT
- SWITCH
Attributes
logger[R]
@return [Logger]
Public Class Methods
_handler(_name)
click to toggle source
@private Just a placeholder for YARD.
# File lib/trema/controller.rb, line 205 def self._handler(_name) # Noop. end
create(port_number = DEFAULT_TCP_PORT, logging_level = ::Logger::INFO)
click to toggle source
@private
# File lib/trema/controller.rb, line 133 def self.create(port_number = DEFAULT_TCP_PORT, logging_level = ::Logger::INFO) unless @controller_klass raise NoControllerDefined, 'No controller class is defined.' end @controller_klass.new(port_number, logging_level) end
inherited(subclass)
click to toggle source
@private
# File lib/trema/controller.rb, line 128 def self.inherited(subclass) @controller_klass = subclass end
new(port_number = DEFAULT_TCP_PORT, logging_level = ::Logger::INFO)
click to toggle source
@private
# File lib/trema/controller.rb, line 142 def initialize(port_number = DEFAULT_TCP_PORT, logging_level = ::Logger::INFO) @port_number = port_number @threads = [] @logger = Logger.new(name) @logger.level = logging_level end
timer_event(handler, options)
click to toggle source
# File lib/trema/controller.rb, line 118 def self.timer_event(handler, options) @timer_handlers ||= {} @timer_handlers[handler] = options.fetch(:interval) end
timer_handlers()
click to toggle source
# File lib/trema/controller.rb, line 123 def self.timer_handlers @timer_handlers || {} end
Public Instance Methods
echo_request(datapath_id, message)
click to toggle source
The default handler for echo request messages. Override this to implement a custom handler.
# File lib/trema/controller.rb, line 223 def echo_request(datapath_id, message) echo_reply = Echo::Reply.new(transaction_id: message.xid) send_message datapath_id, echo_reply end
name()
click to toggle source
# File lib/trema/controller.rb, line 161 def name self.class.name end
run(args)
click to toggle source
@private Starts this controller. Usually you do not need to invoke explicitly, because this is called implicitly by “trema run” command.
# File lib/trema/controller.rb, line 154 def run(args) maybe_send_handler :start, args socket = TCPServer.open('<any>', @port_number) start_timers loop { start_switch_thread(socket.accept) } end
send_flow_mod_add(datapath_id, options)
click to toggle source
@!group OpenFlow Message
# File lib/trema/controller.rb, line 171 def send_flow_mod_add(datapath_id, options) flow_mod = case Pio::OpenFlow.version when 'OpenFlow10' FlowMod.new(FlowModAddOption.new(options).to_hash) when 'OpenFlow13' FlowMod.new(FlowModAdd13Option.new(options).to_hash) else raise "Unsupported OpenFlow version: #{Pio::OpenFlow.version}" end send_message datapath_id, flow_mod end
send_flow_mod_delete(datapath_id, options)
click to toggle source
# File lib/trema/controller.rb, line 184 def send_flow_mod_delete(datapath_id, options) flow_mod = FlowMod.new(FlowModDeleteOption.new(options).to_hash) send_message datapath_id, flow_mod end
send_message(datapath_id, message)
click to toggle source
# File lib/trema/controller.rb, line 194 def send_message(datapath_id, message) SWITCH.fetch(datapath_id).write message rescue KeyError, Errno::ECONNRESET, Errno::EPIPE logger.debug "Switch #{datapath_id} is disconnected." end
send_packet_out(datapath_id, options)
click to toggle source
# File lib/trema/controller.rb, line 189 def send_packet_out(datapath_id, options) packet_out = PacketOut.new(PacketOutOption.new(options).to_hash) send_message datapath_id, packet_out end
stop()
click to toggle source
# File lib/trema/controller.rb, line 165 def stop @threads.map(&:kill) end
Private Instance Methods
create_and_register_new_switch(socket)
click to toggle source
# File lib/trema/controller.rb, line 267 def create_and_register_new_switch(socket) switch = Switch.new(socket) switch.init SWITCH[switch.datapath_id] = switch rescue Switch::InitError error_message = switch.error_message case error_message when OpenFlow10::Error::HelloFailed, OpenFlow13::Error::HelloFailed maybe_send_handler :hello_failed, error_message raise $ERROR_INFO end end
handle_openflow_message(datapath_id)
click to toggle source
rubocop:disable MethodLength rubocop:disable AbcSize rubocop:disable CyclomaticComplexity
# File lib/trema/controller.rb, line 288 def handle_openflow_message(datapath_id) begin message = SWITCH.fetch(datapath_id).read rescue KeyError logger.debug "Switch #{datapath_id} is disconnected." end case message when Echo::Request maybe_send_handler :echo_request, datapath_id, message when Echo::Reply maybe_send_handler :echo_reply, datapath_id, message when Features::Reply maybe_send_handler :features_reply, datapath_id, message when PacketIn message.datapath_id = datapath_id maybe_send_handler :packet_in, datapath_id, message when PortStatus message.datapath_id = datapath_id case message.reason when :add maybe_send_handler :port_add, datapath_id, message when :delete maybe_send_handler :port_delete, datapath_id, message when :modify maybe_send_handler :port_modify, datapath_id, message else raise "Invalid Port Status message: #{message.inspect}" end when Barrier::Reply maybe_send_handler :barrier_reply, datapath_id, message when DescriptionStats::Reply maybe_send_handler :description_stats_reply, datapath_id, message else raise "Unknown OpenFlow message: #{message.inspect}" end end
maybe_send_handler(handler, *args)
click to toggle source
# File lib/trema/controller.rb, line 334 def maybe_send_handler(handler, *args) return unless respond_to?(handler) send_handler(handler, *args) end
send_handler(handler, *args)
click to toggle source
rubocop:enable MethodLength rubocop:enable AbcSize rubocop:enable CyclomaticComplexity
# File lib/trema/controller.rb, line 329 def send_handler(handler, *args) @handler_mutex ||= Mutex.new @handler_mutex.synchronize { __send__(handler, *args) } end
start_switch_main(datapath_id)
click to toggle source
# File lib/trema/controller.rb, line 260 def start_switch_main(datapath_id) maybe_send_handler :switch_ready, datapath_id loop { handle_openflow_message datapath_id } rescue EOFError, IOError unregister_switch datapath_id end
start_switch_thread(socket)
click to toggle source
# File lib/trema/controller.rb, line 251 def start_switch_thread(socket) th = Thread.start(socket) do |sock| switch = create_and_register_new_switch(sock) start_switch_main switch.datapath_id end th.abort_on_exception = true @threads << th end
start_timers()
click to toggle source
@!endgroup
# File lib/trema/controller.rb, line 238 def start_timers self.class.timer_handlers.each do |handler, interval| th = Thread.start(handler, interval) do |method, sec| loop do send_handler method sleep sec end end th.abort_on_exception = true @threads << th end end
unregister_switch(datapath_id)
click to toggle source
# File lib/trema/controller.rb, line 280 def unregister_switch(datapath_id) SWITCH.delete datapath_id maybe_send_handler :switch_disconnected, datapath_id end