openflow-controller 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d03f70b6b79ae5f78ceea79beb46a1c0231c66b5
4
+ data.tar.gz: 175302796e704286f52912508d8e8c3bedbd947f
5
+ SHA512:
6
+ metadata.gz: 2c327dc1711de1ffaa374458189dc7999c9c8db40035be47adf2c3d37add1470df5a514bcfb86f938c256c9f9fad4fd7a9e6925d042e851ccd3e31b3f5bf9bdf
7
+ data.tar.gz: 34465269b491f1ad763d1811624968c9edb9548a77bbcedffdbd9cd77c17705949ef583ef3d1548960ee1aa17376788338cf9536ad0db76b68ee4e62ac93aeb2
@@ -0,0 +1,138 @@
1
+ require 'socket'
2
+ require 'logger'
3
+ require_relative 'switch'
4
+
5
+ class Numeric
6
+ def sec; self end
7
+ end
8
+
9
+ class OFController
10
+ DEFAULT_IP_ADDRESS = '0.0.0.0'
11
+ DEFAULT_TCP_PORT = 6633
12
+
13
+ def self.inherited(subclass)
14
+ @controller_class = subclass
15
+ end
16
+
17
+ def self.create(*args)
18
+ @controller_class.new(*args)
19
+ end
20
+
21
+ def self.timer_event(handler, options)
22
+ @timer_handlers ||= {}
23
+ @timer_handlers[handler] = options.fetch(:interval)
24
+ end
25
+
26
+ def self.timer_handlers
27
+ @timer_handlers || {}
28
+ end
29
+
30
+ attr_reader :logger
31
+
32
+ def initialize(level = Logger::INFO)
33
+ @switches = {}
34
+ @logger = Logger.new($stdout).tap do |logger|
35
+ logger.formatter = proc do |severity, datetime, _progname, msg|
36
+ "#{datetime} (#{severity}) -- #{msg}\n"
37
+ end
38
+ logger.level = level
39
+ end
40
+ end
41
+
42
+ def run(ip, port, *args)
43
+ maybe_send_handler :start, *args
44
+ socket = TCPServer.open(ip, port)
45
+ logger.info "Controller running on #{ip}:#{port}."
46
+ start_timers
47
+ loop { start_switch_thread socket.accept }
48
+ end
49
+
50
+ def send_message(datapath_id, msg)
51
+ @switches.fetch(datapath_id).send(msg)
52
+ end
53
+
54
+ def start(*_args) end
55
+ def switch_ready(_datapath_id) end
56
+ def echo_request(datapath_id, msg)
57
+ send_message datapath_id, OFEchoReply.new(xid: msg.xid)
58
+ end
59
+ def packet_in(_datapath_id, _msg) end
60
+ def port_add(_datapath_id, _msg) end
61
+ def port_delete(_datapath_id, _msg) end
62
+ def port_modify(_datapath_id, _msg) end
63
+ def flow_removed(_datapath_id, _msg) end
64
+
65
+ private
66
+
67
+ def maybe_send_handler(handler, *args)
68
+ @handler_mutex ||= Mutex.new
69
+ @handler_mutex.synchronize do
70
+ __send__(handler, *args) if respond_to?(handler)
71
+ end
72
+ end
73
+
74
+ def start_timers
75
+ self.class.timer_handlers.each do |handler, interval|
76
+ Thread.new do
77
+ loop do
78
+ maybe_send_handler handler
79
+ sleep interval
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ def start_switch_thread(socket)
86
+ logger.debug 'Socket accepted.'
87
+ Thread.new do
88
+ switch = create_and_register_new_switch(socket)
89
+ start_switch_main(switch.datapath_id)
90
+ end
91
+ end
92
+
93
+ def create_and_register_new_switch(socket)
94
+ switch = OFSwitch.new(self, socket)
95
+ @switches[switch.datapath_id] = switch
96
+ end
97
+
98
+ def start_switch_main(datapath_id)
99
+ logger.info "Switch #{datapath_id} is ready."
100
+ maybe_send_handler :switch_ready, datapath_id
101
+ loop { handle_openflow_message(datapath_id) }
102
+ rescue => exception
103
+ logger.debug "Switch #{datapath_id} error: #{exception}."
104
+ unregister_switch(datapath_id)
105
+ end
106
+
107
+ def unregister_switch(datapath_id)
108
+ @switches.delete(datapath_id)
109
+ logger.info "Switch #{datapath_id} is disconnected."
110
+ maybe_send_handler :switch_disconnected, datapath_id
111
+ end
112
+
113
+ def handle_openflow_message(datapath_id)
114
+ msg = @switches.fetch(datapath_id).receive
115
+
116
+ case msg
117
+ when OFEchoRequest
118
+ maybe_send_handler :echo_request, datapath_id, msg
119
+ when OFFeaturesReply
120
+ maybe_send_handler :features_reply, datapath_id, msg
121
+ when OFPacketIn
122
+ maybe_send_handler :packet_in, datapath_id, msg
123
+ when OFPortStatus
124
+ case msg.reason
125
+ when :add
126
+ maybe_send_handler :port_add, datapath_id, msg
127
+ when :delete
128
+ maybe_send_handler :port_delete, datapath_id, msg
129
+ when :modify
130
+ maybe_send_handler :port_modify, datapath_id, msg
131
+ # else
132
+ end
133
+ when OFFlowRemoved
134
+ maybe_send_handler :flow_removed, datapath_id, msg
135
+ # else
136
+ end
137
+ end
138
+ end
@@ -0,0 +1 @@
1
+ require_relative 'controller'
@@ -0,0 +1,52 @@
1
+ require 'openflow-protocol'
2
+
3
+ class OFSwitch
4
+ attr_reader :controller
5
+
6
+ def initialize(controller, socket)
7
+ @controller = controller
8
+ @socket = socket
9
+ begin
10
+ exchange_hello_messages
11
+ exchange_echo_messages
12
+ exchange_features_messages
13
+ rescue => exception
14
+ controller.logger.debug "Switch error: #{exception}."
15
+ raise exception
16
+ end
17
+ end
18
+
19
+ def send(msg)
20
+ @socket.write msg.to_binary_s
21
+ end
22
+
23
+ def receive
24
+ OFParser.read @socket
25
+ end
26
+
27
+ def datapath_id
28
+ @features_reply.datapath_id
29
+ end
30
+
31
+ private
32
+
33
+ def exchange_hello_messages
34
+ controller.logger.debug 'Wait OFPT_HELLO.'
35
+ fail unless receive.is_a?(OFHello)
36
+ send OFHello.new
37
+ end
38
+
39
+ def exchange_echo_messages
40
+ send OFEchoRequest.new
41
+ controller.logger.debug 'Wait OFPT_ECHO_REPLY.'
42
+ fail unless receive.is_a?(OFEchoReply)
43
+ end
44
+
45
+ def exchange_features_messages
46
+ send OFFeaturesRequest.new
47
+ controller.logger.debug 'Wait OFPT_FEATURES_REPLY.'
48
+ @features_reply = receive
49
+ controller.logger.debug "OFPT_FEATURES_REPLY.datapath_id: #{datapath_id}."
50
+ fail unless @features_reply.is_a?(OFFeaturesReply)
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openflow-controller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Jérémy Pagé
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An OpenFlow Controller.
14
+ email:
15
+ - contact@jeremypage.me
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/controller.rb
21
+ - lib/openflow-controller.rb
22
+ - lib/switch.rb
23
+ homepage: https://github.com/jejepage/openflow-controller
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.4.8
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: OpenFlow Controller
47
+ test_files: []