openflow-controller 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99acd8cee866cea479b4d67a120f30ff34a8d37c
4
- data.tar.gz: 235d1054c24087989ab7e8376cd87ce2888ab358
3
+ metadata.gz: 21f97d89fd5cca91d616a17cc08cb2923bc04752
4
+ data.tar.gz: f1025ee07213791f7d3472d8b76026a0ac9ba00f
5
5
  SHA512:
6
- metadata.gz: 64908187a2d746e6847e8f3c0d0fe1c0da44631f419573dee622822a08474a053c5ba2ca2a01b1b4384d11ad05a499f4bd3b3fb82bfad2c440fed3a25a5d5e9b
7
- data.tar.gz: 85f1531795e99ef97a2e38e92c0c63d2163243e9011a4afb91e9eeedddb69688b8566dd985de656faab6058a94e65d731328f8dc3e9618e1dce31cf04c0ba9f2
6
+ metadata.gz: 38f589db1750a5395e5b32efa14a249d06b0530c178fcf649a9c5933ae63cba3f1ce9f3b482f996fc979b6e38e017d4c75d5aa551f82aee3ef201c270fa795c0
7
+ data.tar.gz: 6ed5c77459538dd5a16fabe2689886a1a6360b41512998f62d284fe2b19f43ea9b843649ea4d3ea2544c2c3a97954be8be898562d85d680692678ae51fe39545
data/bin/ofctl CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'cri'
3
3
  require 'readline'
4
- require_relative '../lib/controller'
4
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
5
+ require 'openflow-controller'
5
6
 
6
7
  PROMPT = '> '
7
8
  BYE_MSG = 'Bye!'
@@ -27,7 +28,7 @@ command = Cri::Command.define do
27
28
 
28
29
  debug = opts[:debug] || false
29
30
 
30
- ctl = OFController.create(debug)
31
+ ctl = OpenFlow::Controller::Controller.create(debug)
31
32
 
32
33
  init_form = ctl.logger.formatter
33
34
  ctl.logger.formatter = proc do |severity, datetime, progname, msg|
@@ -37,8 +38,8 @@ command = Cri::Command.define do
37
38
  buf
38
39
  end
39
40
 
40
- ip = opts[:ip] || OFController::DEFAULT_IP_ADDRESS
41
- port = opts[:port] || OFController::DEFAULT_TCP_PORT
41
+ ip = opts[:ip] || OpenFlow::Controller::Controller::DEFAULT_IP_ADDRESS
42
+ port = opts[:port] || OpenFlow::Controller::Controller::DEFAULT_TCP_PORT
42
43
 
43
44
  Thread.abort_on_exception = true
44
45
  Thread.new do
@@ -1 +1,2 @@
1
- require_relative 'controller'
1
+ require 'openflow-controller/version'
2
+ require 'openflow-controller/controller'
@@ -0,0 +1,195 @@
1
+ require 'socket'
2
+ require 'logger'
3
+ require 'openflow-controller/switch'
4
+
5
+ class Numeric
6
+ def sec; self end
7
+ end
8
+
9
+ module OpenFlow
10
+ module Controller
11
+ class Controller
12
+ include Protocol
13
+
14
+ DEFAULT_IP_ADDRESS = '0.0.0.0'
15
+ DEFAULT_TCP_PORT = 6633
16
+
17
+ def self.inherited(subclass)
18
+ @controller_class = subclass
19
+ end
20
+
21
+ def self.create(*args)
22
+ (@controller_class || self).new(*args)
23
+ end
24
+
25
+ def self.timer_event(handler, options)
26
+ @timer_handlers ||= {}
27
+ @timer_handlers[handler] = options.fetch(:interval)
28
+ end
29
+
30
+ def self.timer_handlers
31
+ @timer_handlers || {}
32
+ end
33
+
34
+ attr_reader :logger
35
+
36
+ def initialize(debug = false)
37
+ @switches = {}
38
+ @messages = {}
39
+ @logger = Logger.new($stdout).tap do |logger|
40
+ logger.formatter = proc do |severity, datetime, _progname, msg|
41
+ "#{datetime} (#{severity}) -- #{msg}\n"
42
+ end
43
+ logger.level = debug ? Logger::DEBUG : Logger::INFO
44
+ end
45
+ end
46
+
47
+ def eval(input)
48
+ binding.eval(input)
49
+ end
50
+
51
+ def run(ip = DEFAULT_IP_ADDRESS, port = DEFAULT_TCP_PORT, *args)
52
+ maybe_send_handler :start, *args
53
+ socket = TCPServer.open(ip, port)
54
+ socket.setsockopt(:SOCKET, :REUSEADDR, true)
55
+ logger.info "Controller running on #{ip}:#{port}."
56
+ start_timers
57
+ loop { start_switch_thread socket.accept }
58
+ end
59
+
60
+ def datapath_ids
61
+ @switches.keys.map(&:to_i)
62
+ end
63
+
64
+ def switches
65
+ @switches.values
66
+ end
67
+
68
+ def send_message(datapath_id, msg = nil)
69
+ if msg.nil?
70
+ msg = datapath_id
71
+ datapath_id = datapath_ids.first
72
+ end
73
+ @switches.fetch(datapath_id.to_s).send(msg)
74
+ end
75
+
76
+ def broadcast(msg)
77
+ datapath_ids.each { |did| send_message did, msg }
78
+ end
79
+
80
+ def messages_for(datapath_id)
81
+ @messages.fetch(datapath_id.to_s)
82
+ end
83
+
84
+ def last_message_for(datapath_id)
85
+ messages_for(datapath_id).last
86
+ end
87
+
88
+ def messages
89
+ messages_for datapath_ids.first
90
+ end
91
+
92
+ def last_message
93
+ messages.last
94
+ end
95
+
96
+ def start(*_args) end
97
+ def switch_ready(_datapath_id) end
98
+ def message_received(_datapath_id, _msg) end
99
+ def error(_datapath_id, _msg) end
100
+ def echo_request(datapath_id, msg)
101
+ send_message datapath_id, EchoReply.new(xid: msg.xid)
102
+ end
103
+ def packet_in(_datapath_id, _msg) end
104
+ def port_add(_datapath_id, _msg) end
105
+ def port_delete(_datapath_id, _msg) end
106
+ def port_modify(_datapath_id, _msg) end
107
+ def flow_removed(_datapath_id, _msg) end
108
+
109
+ private
110
+
111
+ def maybe_send_handler(handler, *args)
112
+ @handler_mutex ||= Mutex.new
113
+ @handler_mutex.synchronize do
114
+ __send__(handler, *args) if respond_to?(handler)
115
+ end
116
+ end
117
+
118
+ def start_timers
119
+ self.class.timer_handlers.each do |handler, interval|
120
+ Thread.new do
121
+ loop do
122
+ maybe_send_handler handler
123
+ sleep interval
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def start_switch_thread(socket)
130
+ logger.debug 'Socket accepted.'
131
+ Thread.new do
132
+ switch = create_and_register_new_switch(socket)
133
+ start_switch_main(switch.datapath_id)
134
+ end
135
+ end
136
+
137
+ def create_and_register_new_switch(socket)
138
+ switch = Switch.new(self, socket)
139
+ @messages[switch.datapath_id.to_s] = []
140
+ @switches[switch.datapath_id.to_s] = switch
141
+ end
142
+
143
+ def start_switch_main(datapath_id)
144
+ logger.info "Switch #{datapath_id} is ready."
145
+ maybe_send_handler :switch_ready, datapath_id
146
+ loop { handle_openflow_message(datapath_id) }
147
+ rescue => exception
148
+ logger.debug "Switch #{datapath_id} error: #{exception}."
149
+ logger.debug exception.backtrace
150
+ unregister_switch(datapath_id)
151
+ end
152
+
153
+ def unregister_switch(datapath_id)
154
+ @messages.delete(datapath_id.to_s)
155
+ @switches.delete(datapath_id.to_s)
156
+ logger.info "Switch #{datapath_id} is disconnected."
157
+ maybe_send_handler :switch_disconnected, datapath_id
158
+ end
159
+
160
+ def handle_openflow_message(datapath_id)
161
+ msg = @switches.fetch(datapath_id.to_s).receive
162
+
163
+ unless msg.class == EchoRequest
164
+ logger.debug "Switch #{datapath_id} received #{msg.type} message."
165
+ @messages[datapath_id.to_s] << msg
166
+ maybe_send_handler :message_received, datapath_id, msg
167
+ end
168
+
169
+ case msg
170
+ when Error
171
+ maybe_send_handler :error, datapath_id, msg
172
+ when EchoRequest
173
+ maybe_send_handler :echo_request, datapath_id, msg
174
+ when FeaturesReply
175
+ maybe_send_handler :features_reply, datapath_id, msg
176
+ when PacketIn
177
+ maybe_send_handler :packet_in, datapath_id, msg
178
+ when PortStatus
179
+ case msg.reason
180
+ when :add
181
+ maybe_send_handler :port_add, datapath_id, msg
182
+ when :delete
183
+ maybe_send_handler :port_delete, datapath_id, msg
184
+ when :modify
185
+ maybe_send_handler :port_modify, datapath_id, msg
186
+ # else
187
+ end
188
+ when FlowRemoved
189
+ maybe_send_handler :flow_removed, datapath_id, msg
190
+ # else
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,58 @@
1
+ require 'openflow-protocol'
2
+
3
+ module OpenFlow
4
+ module Controller
5
+ class Switch
6
+ include Protocol
7
+
8
+ attr_reader :controller, :features_reply
9
+
10
+ def initialize(controller, socket)
11
+ @controller = controller
12
+ @socket = socket
13
+ begin
14
+ exchange_hello_messages
15
+ exchange_echo_messages
16
+ exchange_features_messages
17
+ rescue => exception
18
+ controller.logger.debug "Switch error: #{exception}."
19
+ raise exception
20
+ end
21
+ end
22
+
23
+ def send(msg)
24
+ @socket.write msg.to_binary_s
25
+ end
26
+
27
+ def receive
28
+ Parser.read @socket
29
+ end
30
+
31
+ def datapath_id
32
+ @features_reply.datapath_id
33
+ end
34
+
35
+ private
36
+
37
+ def exchange_hello_messages
38
+ controller.logger.debug 'Wait OFPT_HELLO.'
39
+ fail unless receive.is_a?(Hello)
40
+ send Hello.new
41
+ end
42
+
43
+ def exchange_echo_messages
44
+ send EchoRequest.new
45
+ controller.logger.debug 'Wait OFPT_ECHO_REPLY.'
46
+ fail unless receive.is_a?(EchoReply)
47
+ end
48
+
49
+ def exchange_features_messages
50
+ send FeaturesRequest.new
51
+ controller.logger.debug 'Wait OFPT_FEATURES_REPLY.'
52
+ @features_reply = receive
53
+ controller.logger.debug "OFPT_FEATURES_REPLY.datapath_id: #{datapath_id}."
54
+ fail unless @features_reply.is_a?(FeaturesReply)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,5 +1,5 @@
1
1
  module OpenFlow
2
2
  module Controller
3
- VERSION = '0.1.8'
3
+ VERSION = '0.1.9'
4
4
  end
5
5
  end
@@ -1,8 +1,6 @@
1
- require 'spec_helper'
2
-
3
- describe OFController do
1
+ describe Controller do
4
2
  before(:all) do
5
- class MyCtl < OFController
3
+ class MyCtl < Controller
6
4
  attr_reader :start_args
7
5
 
8
6
  def start(*args)
@@ -10,7 +8,7 @@ describe OFController do
10
8
  end
11
9
  end
12
10
 
13
- @ctl = OFController.create
11
+ @ctl = Controller.create
14
12
  Thread.new { @ctl.run('127.0.0.1', 4242, 'Hello World!', 42) }
15
13
  end
16
14
 
@@ -27,20 +25,20 @@ describe OFController do
27
25
  socket = TCPSocket.new '127.0.0.1', 4242
28
26
 
29
27
  # Exchange Hello messages
30
- socket.write OFHello.new.to_binary_s
31
- msg = OFParser.read socket
32
- expect(msg.class).to be(OFHello)
28
+ socket.write Hello.new.to_binary_s
29
+ sleep(0.001)
30
+ msg = Parser.read socket
31
+ expect(msg.class).to be(Hello)
33
32
 
34
33
  # Exchange Echo messages
35
- msg = OFParser.read socket
36
- expect(msg.class).to be(OFEchoRequest)
37
- # socket.write msg.to_reply.to_binary_s
38
- socket.write OFEchoReply.new.to_binary_s
34
+ msg = Parser.read socket
35
+ expect(msg.class).to be(EchoRequest)
36
+ socket.write msg.to_reply.to_binary_s
39
37
 
40
38
  # Exchange Features messages
41
- msg = OFParser.read socket
42
- expect(msg.class).to be(OFFeaturesRequest)
43
- socket.write OFFeaturesReply.new(datapath_id: 1).to_binary_s
39
+ msg = Parser.read socket
40
+ expect(msg.class).to be(FeaturesRequest)
41
+ socket.write FeaturesReply.new(datapath_id: 1).to_binary_s
44
42
 
45
43
  sleep(0.001)
46
44
  expect(@ctl.switches.length).to eq(1)
@@ -1 +1,3 @@
1
- require_relative '../lib/openflow-controller'
1
+ require 'openflow-controller'
2
+ include OpenFlow::Controller
3
+ include OpenFlow::Protocol
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openflow-controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jérémy Pagé
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.7
19
+ version: 0.1.8
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.7
26
+ version: 0.1.8
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: colored
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '2.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.4'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -75,10 +89,10 @@ extensions: []
75
89
  extra_rdoc_files: []
76
90
  files:
77
91
  - bin/ofctl
78
- - lib/controller.rb
79
92
  - lib/openflow-controller.rb
93
+ - lib/openflow-controller/controller.rb
94
+ - lib/openflow-controller/switch.rb
80
95
  - lib/openflow-controller/version.rb
81
- - lib/switch.rb
82
96
  - spec/controller_spec.rb
83
97
  - spec/spec_helper.rb
84
98
  homepage: https://github.com/jejepage/openflow-controller
@@ -1,189 +0,0 @@
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 || self).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(debug = false)
33
- @switches = {}
34
- @messages = {}
35
- @logger = Logger.new($stdout).tap do |logger|
36
- logger.formatter = proc do |severity, datetime, _progname, msg|
37
- "#{datetime} (#{severity}) -- #{msg}\n"
38
- end
39
- logger.level = debug ? Logger::DEBUG : Logger::INFO
40
- end
41
- end
42
-
43
- def eval(input)
44
- binding.eval(input)
45
- end
46
-
47
- def run(ip = DEFAULT_IP_ADDRESS, port = DEFAULT_TCP_PORT, *args)
48
- maybe_send_handler :start, *args
49
- socket = TCPServer.open(ip, port)
50
- socket.setsockopt(:SOCKET, :REUSEADDR, true)
51
- logger.info "Controller running on #{ip}:#{port}."
52
- start_timers
53
- loop { start_switch_thread socket.accept }
54
- end
55
-
56
- def datapath_ids
57
- @switches.keys.map(&:to_i)
58
- end
59
-
60
- def switches
61
- @switches.values
62
- end
63
-
64
- def send_message(datapath_id, msg = nil)
65
- if msg.nil?
66
- msg = datapath_id
67
- datapath_id = datapath_ids.first
68
- end
69
- @switches.fetch(datapath_id.to_s).send(msg)
70
- end
71
-
72
- def broadcast(msg)
73
- datapath_ids.each { |did| send_message did, msg }
74
- end
75
-
76
- def messages_for(datapath_id)
77
- @messages.fetch(datapath_id.to_s)
78
- end
79
-
80
- def last_message_for(datapath_id)
81
- messages_for(datapath_id).last
82
- end
83
-
84
- def messages
85
- messages_for datapath_ids.first
86
- end
87
-
88
- def last_message
89
- messages.last
90
- end
91
-
92
- def start(*_args) end
93
- def switch_ready(_datapath_id) end
94
- def message_received(_datapath_id, _msg) end
95
- def error(_datapath_id, _msg) end
96
- def echo_request(datapath_id, msg)
97
- send_message datapath_id, OFEchoReply.new(xid: msg.xid)
98
- end
99
- def packet_in(_datapath_id, _msg) end
100
- def port_add(_datapath_id, _msg) end
101
- def port_delete(_datapath_id, _msg) end
102
- def port_modify(_datapath_id, _msg) end
103
- def flow_removed(_datapath_id, _msg) end
104
-
105
- private
106
-
107
- def maybe_send_handler(handler, *args)
108
- @handler_mutex ||= Mutex.new
109
- @handler_mutex.synchronize do
110
- __send__(handler, *args) if respond_to?(handler)
111
- end
112
- end
113
-
114
- def start_timers
115
- self.class.timer_handlers.each do |handler, interval|
116
- Thread.new do
117
- loop do
118
- maybe_send_handler handler
119
- sleep interval
120
- end
121
- end
122
- end
123
- end
124
-
125
- def start_switch_thread(socket)
126
- logger.debug 'Socket accepted.'
127
- Thread.new do
128
- switch = create_and_register_new_switch(socket)
129
- start_switch_main(switch.datapath_id)
130
- end
131
- end
132
-
133
- def create_and_register_new_switch(socket)
134
- switch = OFSwitch.new(self, socket)
135
- @messages[switch.datapath_id.to_s] = []
136
- @switches[switch.datapath_id.to_s] = switch
137
- end
138
-
139
- def start_switch_main(datapath_id)
140
- logger.info "Switch #{datapath_id} is ready."
141
- maybe_send_handler :switch_ready, datapath_id
142
- loop { handle_openflow_message(datapath_id) }
143
- rescue => exception
144
- logger.debug "Switch #{datapath_id} error: #{exception}."
145
- logger.debug exception.backtrace
146
- unregister_switch(datapath_id)
147
- end
148
-
149
- def unregister_switch(datapath_id)
150
- @messages.delete(datapath_id.to_s)
151
- @switches.delete(datapath_id.to_s)
152
- logger.info "Switch #{datapath_id} is disconnected."
153
- maybe_send_handler :switch_disconnected, datapath_id
154
- end
155
-
156
- def handle_openflow_message(datapath_id)
157
- msg = @switches.fetch(datapath_id.to_s).receive
158
-
159
- unless msg.class == OFEchoRequest
160
- logger.debug "Switch #{datapath_id} received #{msg.type} message."
161
- @messages[datapath_id.to_s] << msg
162
- maybe_send_handler :message_received, datapath_id, msg
163
- end
164
-
165
- case msg
166
- when OFError
167
- maybe_send_handler :error, datapath_id, msg
168
- when OFEchoRequest
169
- maybe_send_handler :echo_request, datapath_id, msg
170
- when OFFeaturesReply
171
- maybe_send_handler :features_reply, datapath_id, msg
172
- when OFPacketIn
173
- maybe_send_handler :packet_in, datapath_id, msg
174
- when OFPortStatus
175
- case msg.reason
176
- when :add
177
- maybe_send_handler :port_add, datapath_id, msg
178
- when :delete
179
- maybe_send_handler :port_delete, datapath_id, msg
180
- when :modify
181
- maybe_send_handler :port_modify, datapath_id, msg
182
- # else
183
- end
184
- when OFFlowRemoved
185
- maybe_send_handler :flow_removed, datapath_id, msg
186
- # else
187
- end
188
- end
189
- end
@@ -1,52 +0,0 @@
1
- require 'openflow-protocol'
2
-
3
- class OFSwitch
4
- attr_reader :controller, :features_reply
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