openflow-protocol 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/lib/actions/action.rb +26 -0
  3. data/lib/actions/action_enqueue.rb +12 -0
  4. data/lib/actions/action_output.rb +10 -0
  5. data/lib/actions/action_set_destination_port.rb +3 -0
  6. data/lib/actions/action_set_ip_destination.rb +3 -0
  7. data/lib/actions/action_set_ip_source.rb +9 -0
  8. data/lib/actions/action_set_ip_tos.rb +11 -0
  9. data/lib/actions/action_set_mac_destination.rb +3 -0
  10. data/lib/actions/action_set_mac_source.rb +11 -0
  11. data/lib/actions/action_set_source_port.rb +11 -0
  12. data/lib/actions/action_set_vlan_id.rb +11 -0
  13. data/lib/actions/action_set_vlan_pcp.rb +11 -0
  14. data/lib/actions/action_strip_vlan.rb +10 -0
  15. data/lib/actions/action_vendor.rb +9 -0
  16. data/lib/actions/actions.rb +28 -0
  17. data/lib/helpers/enum.rb +45 -0
  18. data/lib/helpers/flags.rb +49 -0
  19. data/lib/helpers/ip_address.rb +14 -0
  20. data/lib/helpers/mac_address.rb +14 -0
  21. data/lib/helpers/superclass_base.rb +21 -0
  22. data/lib/messages/barrier_reply.rb +3 -0
  23. data/lib/messages/barrier_request.rb +3 -0
  24. data/lib/messages/echo_reply.rb +3 -0
  25. data/lib/messages/echo_request.rb +9 -0
  26. data/lib/messages/features_reply.rb +40 -0
  27. data/lib/messages/features_request.rb +3 -0
  28. data/lib/messages/flow_mod.rb +20 -0
  29. data/lib/messages/flow_removed.rb +23 -0
  30. data/lib/messages/get_config_reply.rb +12 -0
  31. data/lib/messages/get_config_request.rb +3 -0
  32. data/lib/messages/hello.rb +3 -0
  33. data/lib/messages/message.rb +45 -0
  34. data/lib/messages/packet_in.rb +17 -0
  35. data/lib/messages/packet_out.rb +13 -0
  36. data/lib/messages/port_mod.rb +13 -0
  37. data/lib/messages/port_status.rb +14 -0
  38. data/lib/messages/set_config.rb +3 -0
  39. data/lib/messages/statistics.rb +24 -0
  40. data/lib/messages/statistics_reply.rb +22 -0
  41. data/lib/messages/statistics_request.rb +14 -0
  42. data/lib/messages/vendor.rb +10 -0
  43. data/lib/openflow-protocol.rb +3 -0
  44. data/lib/statistics/aggregate_statistics_reply.rb +10 -0
  45. data/lib/statistics/aggregate_statistics_request.rb +3 -0
  46. data/lib/statistics/description_statistics.rb +28 -0
  47. data/lib/statistics/flow_statistics_reply.rb +21 -0
  48. data/lib/statistics/flow_statistics_request.rb +10 -0
  49. data/lib/statistics/port_statistics_reply.rb +20 -0
  50. data/lib/statistics/port_statistics_request.rb +8 -0
  51. data/lib/statistics/queue_statistics_reply.rb +12 -0
  52. data/lib/statistics/queue_statistics_request.rb +9 -0
  53. data/lib/statistics/table_statistics.rb +17 -0
  54. data/lib/statistics/vendor_statistics.rb +7 -0
  55. data/lib/structs/match.rb +91 -0
  56. data/lib/structs/physical_port.rb +46 -0
  57. data/lib/structs/port_number.rb +31 -0
  58. metadata +100 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1fc576ecfced9806622867b9ec63625e0547bd50
4
+ data.tar.gz: ed90aa37d49475ab047c38ae85863ba1f3b8d850
5
+ SHA512:
6
+ metadata.gz: 679d1d48ba8ee8f06b36d03a2bc0b626b38f8d203c22bdcadc38c34964171011c734427caab89e71d3dfdeaa63d75cda72cfa623b2b22a9ec418183664d7b97c
7
+ data.tar.gz: 942c5502894b36f8de79c5b5866d129e25587657dbf6102337616dc242534e78432199323ad5df1249ff56c0aea28dba7489a8f7039e77847cb49c91ce069fc2
@@ -0,0 +1,26 @@
1
+ (Dir[File.expand_path '../helpers/**/*.rb', __dir__] +
2
+ Dir[File.expand_path '../structs/**/*.rb', __dir__]).each do |file|
3
+ require file
4
+ end
5
+
6
+ class OFAction < SuperclassBase
7
+ HEADER_LENGTH = 4
8
+ TYPES = [
9
+ :output,
10
+ :set_vlan_id,
11
+ :set_vlan_pcp,
12
+ :strip_vlan,
13
+ :set_mac_source, # set_dl_src
14
+ :set_mac_destination, # set_dl_dst
15
+ :set_ip_source, # set_nw_src
16
+ :set_ip_destination, # set_nw_dst
17
+ :set_ip_tos, # set_nw_tos
18
+ :set_source_port, # set_tp_src
19
+ :set_destination_port, # set_tp_dst
20
+ :enqueue
21
+ ]
22
+ TYPES[0xffff] = :vendor
23
+
24
+ enum16 :type, list: TYPES, asserted_value: -> { type_str.to_sym }
25
+ uint16 :len, value: -> { HEADER_LENGTH + body_length }
26
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionEnqueue < OFAction
4
+ of_port_number :port
5
+ uint48 :padding
6
+ hide :padding
7
+ uint32 :queue_id, initial_value: 0
8
+
9
+ def body_length
10
+ 12
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionOutput < OFAction
4
+ of_port_number :port
5
+ uint16 :max_length, initial_value: 0xffff
6
+
7
+ def body_length
8
+ 4
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'action_set_source_port'
2
+
3
+ class OFActionSetDestinationPort < OFActionSetSourcePort; end
@@ -0,0 +1,3 @@
1
+ require_relative 'action_set_ip_source'
2
+
3
+ class OFActionSetIpDestination < OFActionSetIpSource; end
@@ -0,0 +1,9 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionSetIpSource < OFAction
4
+ ip_address :ip_address
5
+
6
+ def body_length
7
+ 4
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionSetIpTos < OFAction
4
+ uint8 :tos
5
+ uint24 :padding
6
+ hide :padding
7
+
8
+ def body_length
9
+ 4
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'action_set_mac_source'
2
+
3
+ class OFActionSetMacDestination < OFActionSetMacSource; end
@@ -0,0 +1,11 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionSetMacSource < OFAction
4
+ mac_address :mac_address
5
+ uint48 :padding
6
+ hide :padding
7
+
8
+ def body_length
9
+ 12
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionSetSourcePort < OFAction
4
+ uint16 :port, initial_value: 0
5
+ uint16 :padding
6
+ hide :padding
7
+
8
+ def body_length
9
+ 4
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionSetVlanId < OFAction
4
+ uint16 :vlan_id, initial_value: 0
5
+ uint16 :padding
6
+ hide :padding
7
+
8
+ def body_length
9
+ 4
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionSetVlanPcp < OFAction
4
+ uint8 :vlan_pcp, initial_value: 0
5
+ uint24 :padding
6
+ hide :padding
7
+
8
+ def body_length
9
+ 4
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionStripVlan < OFAction
4
+ uint32 :padding
5
+ hide :padding
6
+
7
+ def body_length
8
+ 4
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'action'
2
+
3
+ class OFActionVendor < OFAction
4
+ uint32 :vendor, initial_value: 0
5
+
6
+ def body_length
7
+ 4
8
+ end
9
+ end
@@ -0,0 +1,28 @@
1
+ Dir[File.expand_path 'action_*.rb', __dir__].each do |file|
2
+ require file
3
+ end
4
+
5
+ class OFActions < BinData::Primitive
6
+ default_parameter length: 0
7
+ endian :big
8
+ string :binary, read_length: :length
9
+
10
+ def get
11
+ actions = []
12
+ tmp = binary
13
+ until tmp.empty?
14
+ type_index = BinData::Uint16be.read(tmp)
15
+ type_str = OFAction::TYPES.fetch(type_index)
16
+ class_name = 'OFAction' + type_str.to_s.split('_').map(&:capitalize).join
17
+ klass = Object.const_get class_name
18
+ action = klass.read(tmp)
19
+ actions << action
20
+ tmp = tmp[action.len..-1]
21
+ end
22
+ actions
23
+ end
24
+
25
+ def set(value)
26
+ self.binary = value.map(&:to_binary_s).join
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ require 'bindata'
2
+
3
+ def _def_enum(size)
4
+ eval %(
5
+ class Enum#{size} < BinData::Primitive
6
+ mandatory_parameter :list
7
+
8
+ endian :big
9
+ uint#{size} :enum, initial_value: 0
10
+
11
+ def get
12
+ list.invert.fetch(enum)
13
+ rescue KeyError
14
+ enum
15
+ end
16
+
17
+ def set(value)
18
+ self.enum = list.fetch(value)
19
+ rescue KeyError
20
+ self.enum = value
21
+ end
22
+
23
+ private
24
+
25
+ def list
26
+ list = eval_parameter(:list)
27
+ case list
28
+ when Array
29
+ shift = 0
30
+ list.each_with_object({}) do |each, result|
31
+ result[each] = shift
32
+ shift += 1
33
+ result
34
+ end
35
+ when Hash
36
+ list
37
+ end
38
+ end
39
+ end
40
+ )
41
+ end
42
+
43
+ _def_enum 8
44
+ _def_enum 16
45
+ _def_enum 32
@@ -0,0 +1,49 @@
1
+ require 'bindata'
2
+
3
+ def _def_flags(size)
4
+ eval %(
5
+ class Flags#{size} < BinData::Primitive
6
+ mandatory_parameter :list
7
+
8
+ endian :big
9
+ uint#{size} :flags, initial_value: 0
10
+
11
+ def get
12
+ list.each_with_object([]) do |(key, value), result|
13
+ result << key if (flags & value != 0) || (flags == value)
14
+ result
15
+ end
16
+ end
17
+
18
+ def set(value)
19
+ value.each do |each|
20
+ fail "Invalid flag: \#{value}" unless list.keys.include?(each)
21
+ end
22
+ self.flags = value.empty? ?
23
+ 0 :
24
+ value.map { |each| list[each] }.inject(:|)
25
+ end
26
+
27
+ private
28
+
29
+ def list
30
+ list = eval_parameter(:list)
31
+ case list
32
+ when Array
33
+ shift = 0
34
+ list.each_with_object({}) do |each, result|
35
+ result[each] = 1 << shift
36
+ shift += 1
37
+ result
38
+ end
39
+ when Hash
40
+ list
41
+ end
42
+ end
43
+ end
44
+ )
45
+ end
46
+
47
+ _def_flags 8
48
+ _def_flags 16
49
+ _def_flags 32
@@ -0,0 +1,14 @@
1
+ require 'bindata'
2
+
3
+ class IpAddress < BinData::Primitive
4
+ endian :big
5
+ array :octets, type: :uint8, initial_length: 4
6
+
7
+ def get
8
+ octets.map(&:to_s).join('.')
9
+ end
10
+
11
+ def set(value)
12
+ self.octets = value.split('.').map(&:to_i)
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'bindata'
2
+
3
+ class MacAddress < BinData::Primitive
4
+ endian :big
5
+ array :octets, type: :uint8, initial_length: 6
6
+
7
+ def get
8
+ octets.map { |octet| format('%02x', octet) }.join(':')
9
+ end
10
+
11
+ def set(value)
12
+ self.octets = value.split(':').map(&:hex)
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ require 'bindata'
2
+
3
+ class SuperclassBase < BinData::Record
4
+ attr_reader :type_str
5
+
6
+ endian :big
7
+
8
+ def initialize_instance
9
+ super
10
+ if self.class.name[2..7] == 'Action'
11
+ name = self.class.name[8..-1]
12
+ else
13
+ name = self.class.name[2..-1]
14
+ end
15
+ @type_str = name.gsub(/([A-Z])/, '_\1')[1..-1].downcase
16
+ end
17
+
18
+ def body_length
19
+ 0
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'message'
2
+
3
+ class OFBarrierReply < OFMessage; end
@@ -0,0 +1,3 @@
1
+ require_relative 'message'
2
+
3
+ class OFBarrierRequest < OFMessage; end
@@ -0,0 +1,3 @@
1
+ require_relative 'echo_request'
2
+
3
+ class OFEchoReply < OFEchoRequest; end
@@ -0,0 +1,9 @@
1
+ require_relative 'message'
2
+
3
+ class OFEchoRequest < OFMessage
4
+ rest :data
5
+
6
+ def body_length
7
+ data.length
8
+ end
9
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'message'
2
+
3
+ class OFFeaturesReply < OFMessage
4
+ uint64 :datapath_id, initial_value: 0
5
+ uint32 :n_buffers, initial_value: 0
6
+ uint8 :n_tables, initial_value: 0
7
+ uint24 :padding
8
+ hide :padding
9
+ flags32 :capabilities, list: [
10
+ :flow_stats,
11
+ :table_stats,
12
+ :port_stats,
13
+ :stp,
14
+ :reserved,
15
+ :ip_reasm,
16
+ :queue_stats,
17
+ :arp_match_ip
18
+ ]
19
+ flags32 :actions, list: [
20
+ :output,
21
+ :set_vlan_vid,
22
+ :set_vlan_pcp,
23
+ :strip_vlan,
24
+ :set_dl_src,
25
+ :set_dl_dst,
26
+ :set_nw_src,
27
+ :set_nw_dst,
28
+ :set_nw_tos,
29
+ :set_tp_src,
30
+ :set_tp_dst,
31
+ :enqueue
32
+ ]
33
+ array :ports,
34
+ type: :of_physical_port,
35
+ initial_length: -> { (len - ports.rel_offset) / 48 }
36
+
37
+ def body_length
38
+ 24 + ports.to_binary_s.length
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'message'
2
+
3
+ class OFFeaturesRequest < OFMessage; end
@@ -0,0 +1,20 @@
1
+ require_relative 'message'
2
+
3
+ class OFFlowMod < OFMessage
4
+ of_match :match
5
+ uint64 :cookie, initial_value: 0
6
+ enum16 :command, list: [:add, :modify, :modify_strict, :delete, :delete_strict]
7
+ uint16 :idle_timeout, initial_value: 0
8
+ uint16 :hard_timeout, initial_value: 0
9
+ uint16 :priority, initial_value: 0
10
+ uint32 :buffer_id, initial_value: 0xffffffff
11
+ of_port_number :out_port, initial_value: (lambda do
12
+ /^delete/ =~ command.to_s ? :none : 0
13
+ end)
14
+ flags16 :flags, list: [:send_flow_removed, :check_overlapping, :emergency]
15
+ of_actions :actions, length: -> { len - actions.rel_offset }
16
+
17
+ def body_length
18
+ 64 + actions.to_binary_s.length
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'message'
2
+
3
+ class OFFlowRemoved < OFMessage
4
+ REASONS = [:idle_timeout, :hard_timeout, :delete]
5
+
6
+ of_match :match
7
+ uint64 :cookie, initial_value: 0
8
+ uint16 :priority, initial_value: 0
9
+ enum8 :reason, list: REASONS
10
+ uint8 :padding
11
+ hide :padding
12
+ uint32 :duration_seconds, initial_value: 0
13
+ uint32 :duration_nanoseconds, initial_value: 0
14
+ uint16 :idle_timeout, initial_value: 0
15
+ uint16 :padding2
16
+ hide :padding2
17
+ uint64 :packet_count, initial_value: 0
18
+ uint64 :byte_count, initial_value: 0
19
+
20
+ def body_length
21
+ 80
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'message'
2
+
3
+ class OFGetConfigReply < OFMessage
4
+ FLAGS = [:fragments_normal, :fragments_drop, :fragments_reassemble]
5
+
6
+ enum16 :flags, list: FLAGS
7
+ uint16 :miss_send_length, initial_value: 0
8
+
9
+ def body_length
10
+ 4
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'message'
2
+
3
+ class OFGetConfigRequest < OFMessage; end
@@ -0,0 +1,3 @@
1
+ require_relative 'message'
2
+
3
+ class OFHello < OFMessage; end
@@ -0,0 +1,45 @@
1
+ (Dir[File.expand_path '../helpers/**/*.rb', __dir__] +
2
+ Dir[File.expand_path '../structs/**/*.rb', __dir__] +
3
+ Dir[File.expand_path '../actions/**/*.rb', __dir__] +
4
+ Dir[File.expand_path '../statistics/**/*.rb', __dir__]).each do |file|
5
+ require file
6
+ end
7
+
8
+ # TODO: use OFPT_, OFPP_, OFPQ_, ... in place of Symbols?
9
+ # check: https://github.com/noxrepo/pox/blob/carp/pox/openflow/libopenflow_01.py
10
+ # -> see decorators
11
+ # ruby decorators: https://github.com/fredwu/ruby_decorators
12
+
13
+ class OFMessage < SuperclassBase
14
+ OFP_VERSION = 0x1
15
+ HEADER_LENGTH = 8
16
+ TYPES = [
17
+ :hello,
18
+ :error, # TODO
19
+ :echo_request,
20
+ :echo_reply,
21
+ :vendor,
22
+ :features_request,
23
+ :features_reply,
24
+ :get_config_request,
25
+ :get_config_reply,
26
+ :set_config,
27
+ :packet_in,
28
+ :flow_removed,
29
+ :port_status,
30
+ :packet_out,
31
+ :flow_mod,
32
+ :port_mod,
33
+ :statistics_request,
34
+ :statistics_reply,
35
+ :barrier_request,
36
+ :barrier_reply,
37
+ :queue_get_config_request, # TODO
38
+ :queue_get_config_reply # TODO
39
+ ]
40
+
41
+ uint8 :version, asserted_value: OFP_VERSION
42
+ enum8 :type, list: TYPES, asserted_value: -> { type_str.to_sym }
43
+ uint16 :len, value: -> { HEADER_LENGTH + body_length }
44
+ uint32 :xid, initial_value: 0
45
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'message'
2
+
3
+ class OFPacketIn < OFMessage
4
+ REASONS = [:no_match, :action]
5
+
6
+ enum32 :buffer_id, list: {none: 0xffffffff}, initial_value: -> { :none }
7
+ uint16 :total_length, value: -> { data.length }
8
+ of_port_number :in_port
9
+ enum8 :reason, list: REASONS
10
+ uint8 :padding
11
+ hide :padding
12
+ string :data, read_length: :total_length
13
+
14
+ def body_length
15
+ 10 + data.length
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'message'
2
+
3
+ class OFPacketOut < OFMessage
4
+ enum32 :buffer_id, list: {none: 0xffffffff}, initial_value: -> { :none }
5
+ of_port_number :in_port
6
+ uint16 :actions_length, value: -> { actions.to_binary_s.length }
7
+ of_actions :actions, length: -> { actions_length }
8
+ string :data, read_length: -> { len - data.rel_offset }
9
+
10
+ def body_length
11
+ 8 + actions_length + data.length
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'message'
2
+
3
+ class OFPortMod < OFMessage
4
+ of_port_number :port_number
5
+ mac_address :hardware_address
6
+ flags32 :config, list: OFPhysicalPort::CONFIG
7
+ flags32 :mask, list: OFPhysicalPort::CONFIG
8
+ flags32 :advertise, list: OFPhysicalPort::FEATURES
9
+
10
+ def body_length
11
+ 24
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'message'
2
+
3
+ class OFPortStatus < OFMessage
4
+ REASONS = [:add, :delete, :modify]
5
+
6
+ enum8 :reason, list: REASONS
7
+ uint56 :padding
8
+ hide :padding
9
+ of_physical_port :desc
10
+
11
+ def body_length
12
+ 56
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'get_config_reply'
2
+
3
+ class OFSetConfig < OFGetConfigReply; end
@@ -0,0 +1,24 @@
1
+ require_relative 'message'
2
+
3
+ class OFStatistics < OFMessage
4
+ STATISTICS_TYPES = [
5
+ :description,
6
+ :flow,
7
+ :aggregate,
8
+ :table,
9
+ :port,
10
+ :queue
11
+ ]
12
+ STATISTICS_TYPES[0xffff] = :vendor
13
+
14
+ def flags_list
15
+ self.class.const_get(:FLAGS)
16
+ end
17
+
18
+ enum16 :statistic_type, list: STATISTICS_TYPES
19
+ flags16 :flags, list: -> { flags_list }
20
+
21
+ def body_length
22
+ 4 + statistics.to_binary_s.length
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'statistics'
2
+
3
+ class OFStatisticsReply < OFStatistics
4
+ FLAGS = [:reply_more]
5
+
6
+ choice :statistics, selection: -> { statistic_type.to_s } do
7
+ of_description_statistics 'description'
8
+ of_flow_statistics_reply 'flow'
9
+ of_aggregate_statistics_reply 'aggregate'
10
+ array 'table',
11
+ type: :of_table_statistics,
12
+ initial_length: -> { (len - statistics.rel_offset) / 64 }
13
+ array 'port',
14
+ type: :of_port_statistics_reply,
15
+ initial_length: -> { (len - statistics.rel_offset) / 104 }
16
+ array 'queue',
17
+ type: :of_queue_statistics_reply,
18
+ initial_length: -> { (len - statistics.rel_offset) / 32 }
19
+ of_vendor_statistics 'vendor'
20
+ rest :default
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'statistics'
2
+
3
+ class OFStatisticsRequest < OFStatistics
4
+ FLAGS = []
5
+
6
+ choice :statistics, selection: -> { statistic_type.to_s } do
7
+ of_flow_statistics_request 'flow'
8
+ of_aggregate_statistics_request 'aggregate'
9
+ of_port_statistics_request 'port'
10
+ of_queue_statistics_request 'queue'
11
+ of_vendor_statistics 'vendor'
12
+ rest :default
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'message'
2
+
3
+ class OFVendor < OFMessage
4
+ uint32 :vendor, initial_value: 0
5
+ rest :data
6
+
7
+ def body_length
8
+ 4 + data.length
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ Dir[File.expand_path 'messages/**/*.rb', __dir__].each do |file|
2
+ require file
3
+ end
@@ -0,0 +1,10 @@
1
+ require 'bindata'
2
+
3
+ class OFAggregateStatisticsReply < BinData::Record
4
+ endian :big
5
+ uint64 :packet_count, initial_value: 0
6
+ uint64 :byte_count, initial_value: 0
7
+ uint32 :flow_count, initial_value: 0
8
+ uint32 :padding
9
+ hide :padding
10
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'flow_statistics_request'
2
+
3
+ class OFAggregateStatisticsRequest < OFFlowStatisticsRequest; end
@@ -0,0 +1,28 @@
1
+ require 'bindata'
2
+
3
+ class OFDescriptionStatistics < BinData::Record
4
+ DESCRIPTION_LENGTH = 256
5
+ SERIAL_NUMBER_LENGTH = 32
6
+
7
+ endian :big
8
+ string :manufacturer_description,
9
+ length: DESCRIPTION_LENGTH,
10
+ trim_padding: true,
11
+ initial_value: ''
12
+ string :hardware_description,
13
+ length: DESCRIPTION_LENGTH,
14
+ trim_padding: true,
15
+ initial_value: ''
16
+ string :software_description,
17
+ length: DESCRIPTION_LENGTH,
18
+ trim_padding: true,
19
+ initial_value: ''
20
+ string :serial_number,
21
+ length: SERIAL_NUMBER_LENGTH,
22
+ trim_padding: true,
23
+ initial_value: ''
24
+ string :datapath_description,
25
+ length: DESCRIPTION_LENGTH,
26
+ trim_padding: true,
27
+ initial_value: ''
28
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'table_statistics'
2
+
3
+ class OFFlowStatisticsReply < BinData::Record
4
+ endian :big
5
+ uint16 :len, initial_value: -> { 88 + actions.to_binary_s.length }
6
+ enum8 :table_id, list: OFTableStatistics::TABLE_IDS, initial_value: -> { :all }
7
+ uint8 :padding
8
+ hide :padding
9
+ of_match :match
10
+ uint32 :duration_seconds, initial_value: 0
11
+ uint32 :duration_nanoseconds, initial_value: 0
12
+ uint16 :priority, initial_value: 0
13
+ uint16 :idle_timeout, initial_value: 0
14
+ uint16 :hard_timeout, initial_value: 0
15
+ uint48 :padding2
16
+ hide :padding2
17
+ uint64 :cookie, initial_value: 0
18
+ uint64 :packet_count, initial_value: 0
19
+ uint64 :byte_count, initial_value: 0
20
+ of_actions :actions, length: -> { len - actions.rel_offset }
21
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'table_statistics'
2
+
3
+ class OFFlowStatisticsRequest < BinData::Record
4
+ endian :big
5
+ of_match :match
6
+ enum8 :table_id, list: OFTableStatistics::TABLE_IDS, initial_value: -> { :all }
7
+ uint8 :padding
8
+ hide :padding
9
+ of_port_number :out_port, initial_value: -> { :none }
10
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../structs/port_number'
2
+
3
+ class OFPortStatisticsReply < BinData::Record
4
+ endian :big
5
+ of_port_number :port_number, initial_value: 0
6
+ uint48 :padding
7
+ hide :padding
8
+ uint64 :receive_packets, initial_value: 0
9
+ uint64 :transmit_packets, initial_value: 0
10
+ uint64 :receive_bytes, initial_value: 0
11
+ uint64 :transmit_bytes, initial_value: 0
12
+ uint64 :receive_dropped, initial_value: 0
13
+ uint64 :transmit_dropped, initial_value: 0
14
+ uint64 :receive_errors, initial_value: 0
15
+ uint64 :transmit_errors, initial_value: 0
16
+ uint64 :receive_frame_errors, initial_value: 0
17
+ uint64 :receive_overrun_errors, initial_value: 0
18
+ uint64 :receive_crc_errors, initial_value: 0
19
+ uint64 :collisions, initial_value: 0
20
+ end
@@ -0,0 +1,8 @@
1
+ require_relative '../structs/port_number'
2
+
3
+ class OFPortStatisticsRequest < BinData::Record
4
+ endian :big
5
+ of_port_number :port_number, initial_value: -> { :none } # all ports
6
+ uint48 :padding
7
+ hide :padding
8
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../structs/port_number'
2
+
3
+ class OFQueueStatisticsReply < BinData::Record
4
+ endian :big
5
+ of_port_number :port_number, initial_value: 0
6
+ uint16 :padding
7
+ hide :padding
8
+ uint32 :queue_id, initial_value: 0
9
+ uint64 :transmit_bytes, initial_value: 0
10
+ uint64 :transmit_packets, initial_value: 0
11
+ uint64 :transmit_errors, initial_value: 0
12
+ end
@@ -0,0 +1,9 @@
1
+ require_relative '../structs/port_number'
2
+
3
+ class OFQueueStatisticsRequest < BinData::Record
4
+ endian :big
5
+ of_port_number :port_number, initial_value: -> { :all }
6
+ uint16 :padding
7
+ hide :padding
8
+ enum32 :queue_id, list: {all: 0xffffffff}, initial_value: -> { :all }
9
+ end
@@ -0,0 +1,17 @@
1
+ require_relative '../structs/match'
2
+ require_relative '../helpers/flags'
3
+
4
+ class OFTableStatistics < BinData::Record
5
+ TABLE_IDS = {emergency: 0xfe, all: 0xff}
6
+
7
+ endian :big
8
+ enum8 :table_id, list: TABLE_IDS, initial_value: 0
9
+ uint24 :padding
10
+ hide :padding
11
+ string :name, length: 32, trim_padding: true, initial_value: ''
12
+ flags32 :wildcards, list: OFMatch::Wildcards::FLAGS
13
+ uint32 :max_entries, initial_value: 0
14
+ uint32 :active_count, initial_value: 0
15
+ uint64 :lookup_count, initial_value: 0
16
+ uint64 :matched_count, initial_value: 0
17
+ end
@@ -0,0 +1,7 @@
1
+ require 'bindata'
2
+
3
+ class OFVendorStatistics < BinData::Record
4
+ endian :big
5
+ uint32 :vendor, initial_value: 0
6
+ rest :body
7
+ end
@@ -0,0 +1,91 @@
1
+ require 'English'
2
+ require_relative '../helpers/enum'
3
+ require_relative '../helpers/mac_address'
4
+ require_relative '../helpers/ip_address'
5
+ require_relative 'port_number'
6
+
7
+ class OFMatch < BinData::Record
8
+ class Wildcards < BinData::Primitive
9
+ FLAGS = {
10
+ in_port: 1 << 0,
11
+ vlan_id: 1 << 1,
12
+ mac_source: 1 << 2,
13
+ mac_destination: 1 << 3,
14
+ mac_protocol: 1 << 4,
15
+ ip_protocol: 1 << 5,
16
+ source_port: 1 << 6,
17
+ destination_port: 1 << 7,
18
+ ip_source0: 1 << 8,
19
+ ip_source1: 1 << 9,
20
+ ip_source2: 1 << 10,
21
+ ip_source3: 1 << 11,
22
+ ip_source4: 1 << 12,
23
+ ip_source_all: 1 << 13,
24
+ ip_destination0: 1 << 14,
25
+ ip_destination1: 1 << 15,
26
+ ip_destination2: 1 << 16,
27
+ ip_destination3: 1 << 17,
28
+ ip_destination4: 1 << 18,
29
+ ip_destination_all: 1 << 19,
30
+ vlan_pcp: 1 << 20,
31
+ ip_tos: 1 << 21
32
+ }
33
+ ALL_FLAGS = Hash[
34
+ FLAGS.keys.select { |key| /^ip_(source|destination)\d$/ !~ key }
35
+ .map { |key| [key, true] }
36
+ ]
37
+
38
+ endian :big
39
+ uint32 :flags, initial_value: 0x003820ff # all
40
+
41
+ def get
42
+ FLAGS.each_with_object(Hash.new(0)) do |(key, bit), memo|
43
+ next if flags & bit == 0
44
+ if /^(ip_source|ip_destination)(\d)/ =~ key
45
+ memo[$LAST_MATCH_INFO[1].to_sym] |= 1 << $LAST_MATCH_INFO[2].to_i
46
+ else
47
+ memo[key] = true
48
+ end
49
+ end
50
+ end
51
+
52
+ def set(value)
53
+ self.flags = value.inject(0) do |memo, (key, val)|
54
+ memo |
55
+ case key
56
+ when :ip_source, :ip_destination
57
+ (val & 31) << (key == :ip_source ? 8 : 14)
58
+ else
59
+ val ? FLAGS.fetch(key) : 0
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ endian :big
66
+ wildcards :wildcards
67
+ of_port_number :in_port, initial_value: 0
68
+ mac_address :mac_source
69
+ mac_address :mac_destination
70
+ uint16 :vlan_id, initial_value: 0xffff
71
+ uint8 :vlan_pcp, initial_value: 0
72
+ uint8 :padding
73
+ hide :padding
74
+ enum16 :mac_protocol, list: {
75
+ ip: 0x0800,
76
+ arp: 0x0806,
77
+ vlan: 0x8100
78
+ }, initial_value: 0
79
+ uint8 :ip_tos, initial_value: 0
80
+ enum8 :ip_protocol, list: {
81
+ icmp: 1,
82
+ tcp: 6,
83
+ udp: 17
84
+ }, initial_value: 0
85
+ uint16 :padding2
86
+ hide :padding2
87
+ ip_address :ip_source
88
+ ip_address :ip_destination
89
+ uint16 :source_port, initial_value: 0
90
+ uint16 :destination_port, initial_value: 0
91
+ end
@@ -0,0 +1,46 @@
1
+ require_relative 'port_number'
2
+ require_relative '../helpers/mac_address'
3
+
4
+ class OFPhysicalPort < BinData::Record
5
+ CONFIG = [
6
+ :port_down,
7
+ :no_spanning_tree,
8
+ :no_receive,
9
+ :no_receive_spanning_tree,
10
+ :no_flood,
11
+ :no_forward,
12
+ :no_packet_in
13
+ ]
14
+ STATE = {
15
+ link_down: 1 << 0,
16
+ spanning_tree_listen: 0 << 8,
17
+ spanning_tree_learn: 1 << 8,
18
+ spanning_tree_forward: 2 << 8,
19
+ spanning_tree_block: 3 << 8
20
+ }
21
+ FEATURES = [
22
+ :port_10mb_half_duplex,
23
+ :port_10mb_full_duplex,
24
+ :port_100mb_half_duplex,
25
+ :port_100mb_full_duplex,
26
+ :port_1gb_half_duplex,
27
+ :port_1gb_full_duplex,
28
+ :port_10gb_full_duplex,
29
+ :port_copper,
30
+ :port_fiber,
31
+ :port_auto_negotiation,
32
+ :port_pause,
33
+ :port_pause_asymmetric
34
+ ]
35
+
36
+ endian :big
37
+ of_port_number :port_number, initial_value: 0
38
+ mac_address :hardware_address
39
+ string :name, length: 16, trim_padding: true, initial_value: ''
40
+ flags32 :config, list: CONFIG
41
+ flags32 :state, list: STATE
42
+ flags32 :current_features, list: FEATURES
43
+ flags32 :advertised_features, list: FEATURES
44
+ flags32 :supported_features, list: FEATURES
45
+ flags32 :peer_features, list: FEATURES
46
+ end
@@ -0,0 +1,31 @@
1
+ require 'bindata'
2
+
3
+ class OFPortNumber < BinData::Primitive
4
+ NUMBERS = {
5
+ in_port: 0xfff8,
6
+ table: 0xfff9,
7
+ normal: 0xfffa,
8
+ flood: 0xfffb,
9
+ all: 0xfffc,
10
+ controller: 0xfffd,
11
+ local: 0xfffe,
12
+ none: 0xffff
13
+ }
14
+ MAX = 0xff00
15
+
16
+ endian :big
17
+ uint16 :port_number, initial_value: NUMBERS[:none]
18
+
19
+ def get
20
+ NUMBERS.invert.fetch(port_number)
21
+ rescue KeyError
22
+ port_number
23
+ end
24
+
25
+ def set(value)
26
+ self.port_number = NUMBERS.fetch(value)
27
+ rescue KeyError
28
+ raise ArgumentError, 'Invalid port number.' unless (0..MAX).include? value
29
+ self.port_number = value
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openflow-protocol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Page
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An OpenFlow Parser/Serializer.
14
+ email:
15
+ - jeremy@jeremypage.me
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/actions/action.rb
21
+ - lib/actions/action_enqueue.rb
22
+ - lib/actions/action_output.rb
23
+ - lib/actions/action_set_destination_port.rb
24
+ - lib/actions/action_set_ip_destination.rb
25
+ - lib/actions/action_set_ip_source.rb
26
+ - lib/actions/action_set_ip_tos.rb
27
+ - lib/actions/action_set_mac_destination.rb
28
+ - lib/actions/action_set_mac_source.rb
29
+ - lib/actions/action_set_source_port.rb
30
+ - lib/actions/action_set_vlan_id.rb
31
+ - lib/actions/action_set_vlan_pcp.rb
32
+ - lib/actions/action_strip_vlan.rb
33
+ - lib/actions/action_vendor.rb
34
+ - lib/actions/actions.rb
35
+ - lib/helpers/enum.rb
36
+ - lib/helpers/flags.rb
37
+ - lib/helpers/ip_address.rb
38
+ - lib/helpers/mac_address.rb
39
+ - lib/helpers/superclass_base.rb
40
+ - lib/messages/barrier_reply.rb
41
+ - lib/messages/barrier_request.rb
42
+ - lib/messages/echo_reply.rb
43
+ - lib/messages/echo_request.rb
44
+ - lib/messages/features_reply.rb
45
+ - lib/messages/features_request.rb
46
+ - lib/messages/flow_mod.rb
47
+ - lib/messages/flow_removed.rb
48
+ - lib/messages/get_config_reply.rb
49
+ - lib/messages/get_config_request.rb
50
+ - lib/messages/hello.rb
51
+ - lib/messages/message.rb
52
+ - lib/messages/packet_in.rb
53
+ - lib/messages/packet_out.rb
54
+ - lib/messages/port_mod.rb
55
+ - lib/messages/port_status.rb
56
+ - lib/messages/set_config.rb
57
+ - lib/messages/statistics.rb
58
+ - lib/messages/statistics_reply.rb
59
+ - lib/messages/statistics_request.rb
60
+ - lib/messages/vendor.rb
61
+ - lib/openflow-protocol.rb
62
+ - lib/statistics/aggregate_statistics_reply.rb
63
+ - lib/statistics/aggregate_statistics_request.rb
64
+ - lib/statistics/description_statistics.rb
65
+ - lib/statistics/flow_statistics_reply.rb
66
+ - lib/statistics/flow_statistics_request.rb
67
+ - lib/statistics/port_statistics_reply.rb
68
+ - lib/statistics/port_statistics_request.rb
69
+ - lib/statistics/queue_statistics_reply.rb
70
+ - lib/statistics/queue_statistics_request.rb
71
+ - lib/statistics/table_statistics.rb
72
+ - lib/statistics/vendor_statistics.rb
73
+ - lib/structs/match.rb
74
+ - lib/structs/physical_port.rb
75
+ - lib/structs/port_number.rb
76
+ homepage: https://github.com/jejepage/openflow-protocol
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.6
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: OpenFlow Protocol
100
+ test_files: []