openflow-controller 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []