openflow-protocol 0.0.1

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.
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: []