diff --git a/.reek b/.reek index a0a457ff..480d66d9 100644 --- a/.reek +++ b/.reek @@ -1,2 +1,15 @@ UncommunicativeModuleName: - accept: ['Pio::Hello13', 'Pio::OpenFlow10', 'Pio::OpenFlow13', 'Pio::OpenFlow10::Port16', 'Pio::OpenFlow10::PhyPort16', 'Pio::OpenFlow10::ErrorType10', 'Pio::OpenFlow10::MatchOpenFlow10', 'Pio::OpenFlow13::Error::ErrorType13', 'Pio::OpenFlow10::Port32',] + accept: ['Pio::Hello13', + 'Pio::OpenFlow10::Error::ErrorType10', + 'Pio::OpenFlow10::Match10', + 'Pio::OpenFlow10::MatchOpenFlow10', + 'Pio::OpenFlow10::PhyPort16', + 'Pio::OpenFlow10::Port16', + 'Pio::OpenFlow10::Port32', + 'Pio::OpenFlow13', + 'Pio::OpenFlow13::Error::ErrorType13', + 'Pio::OpenFlow13::Port32', + 'Pio::OpenFlow10'] + +TooManyStatements: + enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index cd9c63fb..39eb615d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ ## develop (unreleased) +## 0.27.0 (9/16/2015) +### New features +* [#203](https://github.com/trema/pio/pull/203): Add new classes `Pio::OpenFlow10::DescriptionStats::Request`, `Pio::OpenFlow10::DescriptionStats::Reply`, `Pio::OpenFlow10::FlowStats::Request`, `Pio::OpenFlow10::FlowStats::Reply`, `Pio::OpenFlow10::AggregateStats::Request`, `Pio::OpenFlow10::AggregateStats::Reply`. + + ## 0.26.0 (9/8/2015) ### New features * [#214](https://github.com/trema/pio/pull/214): Add new class `Pio::OpenFlow10::Error::HelloFailed`. diff --git a/README.md b/README.md index 3729ea48..511dc030 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,21 @@ pio pencil -Pio is a ruby gem to easily parse and generate network packets. It -supports the following packet formats: +Pio is a ruby gem to easily parse and generate network packets. + +## Features Overview + +- Pure Ruby. No additional dependency on other external tools to + parse/generate packets. +- Multi-Platform. Runs on major operating systems (recent Windows, + Linux, and MacOSX). +- Clean Code. Pio is built on + [BinData](https://github.com/dmendel/bindata)'s declarative binary + format DSL so that it is easy to read and debug by human beings. + +## Supported packet formats + +Pio supports the following packet formats: - [ICMP](https://relishapp.com/trema/pio/docs/pio-icmp) - [ARP](https://relishapp.com/trema/pio/docs/pio-arp) @@ -33,8 +46,12 @@ supports the following packet formats: - [Exact Match](https://relishapp.com/trema/pio/docs/open-flow10/pio-exactmatch) - [Barrier Request](https://relishapp.com/trema/pio/docs/open-flow10/pio-barrier-request) - [Barrier Reply](https://relishapp.com/trema/pio/docs/open-flow10/pio-barrier-reply) + - [Description Stats Request](https://relishapp.com/trema/pio/docs/open-flow10/pio-descriptionstats-request) + - [Description Stats Reply](https://relishapp.com/trema/pio/docs/open-flow10/pio-descriptionstats-reply) - [Flow Stats Request](https://relishapp.com/trema/pio/docs/open-flow10/pio-flowstats-request) - [Flow Stats Reply](https://relishapp.com/trema/pio/docs/open-flow10/pio-flowstats-reply) + - [Aggregate Stats Request](https://relishapp.com/trema/pio/docs/open-flow10/pio-aggregatestats-request) + - [Aggregate Stats Reply](https://relishapp.com/trema/pio/docs/open-flow10/pio-aggregatestats-reply) - OpenFlow 1.3 - [Hello](https://relishapp.com/trema/pio/docs/open-flow13/pio-hello) - [HelloFailed](https://relishapp.com/trema/pio/docs/open-flow13/pio-error-hellofailed) @@ -47,16 +64,6 @@ supports the following packet formats: - [Packet Out](https://relishapp.com/trema/pio/docs/open-flow13/pio-packetout) - [Flow Mod](https://relishapp.com/trema/pio/docs/open-flow13/pio-flowmod) -## Features Overview - -- Pure Ruby. No additional dependency on other external tools to - parse/generate packets. -- Multi-Platform. Runs on major operating systems (recent Windows, - Linux, and MacOSX). -- Clean Code. Pio is built on - [BinData](https://github.com/dmendel/bindata)'s declarative binary - format DSL so that it is easy to read and debug by human beings. - ## Installation The simplest way to install Pio is to use [Bundler](http://gembundler.com/). @@ -75,7 +82,7 @@ bundle ## Documents -- [API document generated with YARD](http://rubydoc.info/github/trema/pio/frames/file/README.md) +- [API document](https://relishapp.com/trema/pio/docs) ## Team diff --git a/Rakefile b/Rakefile index aa2aacc7..275af30d 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ require 'bundler/gem_tasks' RELISH_PROJECT = 'trema/pio' -FLAY_THRESHOLD = 863 +FLAY_THRESHOLD = 919 task default: :travis task test: [:spec, :cucumber] diff --git a/features/open_flow10/aggregate_stats_reply.feature b/features/open_flow10/aggregate_stats_reply.feature new file mode 100644 index 00000000..ca6817cd --- /dev/null +++ b/features/open_flow10/aggregate_stats_reply.feature @@ -0,0 +1,17 @@ +@open_flow10 +Feature: Pio::AggregateStats::Reply + Scenario: read + When I try to parse a file named "open_flow10/aggregate_stats_reply.raw" with "AggregateStats::Reply" class + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 17 | + | length | 36 | + | transaction_id | 15 | + | xid | 15 | + | stats_type | :aggregate | + | flags | 0 | + | packet_count | 0 | + | byte_count | 0 | + | flow_count | 0 | diff --git a/features/open_flow10/aggregate_stats_request.feature b/features/open_flow10/aggregate_stats_request.feature new file mode 100644 index 00000000..480b3647 --- /dev/null +++ b/features/open_flow10/aggregate_stats_request.feature @@ -0,0 +1,60 @@ +@open_flow10 +Feature: Pio::AggregateStats::Request + Scenario: new + When I try to create an OpenFlow message with: + """ + Pio::AggregateStats::Request.new(match: Match.new(in_port: 1)) + """ + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 16 | + | length | 56 | + | transaction_id | 0 | + | xid | 0 | + | stats_type | :aggregate | + | match.in_port | 1 | + | match.wildcards.keys.size | 11 | + | match.wildcards.fetch(:ether_destination_address) | true | + | match.wildcards.fetch(:ether_source_address) | true | + | match.wildcards.fetch(:ether_type) | true | + | match.wildcards.fetch(:ip_destination_address_all) | true | + | match.wildcards.fetch(:ip_protocol) | true | + | match.wildcards.fetch(:ip_source_address_all) | true | + | match.wildcards.fetch(:ip_tos) | true | + | match.wildcards.fetch(:transport_destination_port) | true | + | match.wildcards.fetch(:transport_source_port) | true | + | match.wildcards.fetch(:vlan_priority) | true | + | match.wildcards.fetch(:vlan_vid) | true | + | table_id.to_hex | 0xff | + | out_port | :none | + + + Scenario: read + When I try to parse a file named "open_flow10/aggregate_stats_request.raw" with "AggregateStats::Request" class + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 16 | + | length | 56 | + | transaction_id | 14 | + | xid | 14 | + | stats_type | :aggregate | + | match.wildcards.keys.size | 12 | + | match.wildcards.fetch(:ether_destination_address) | true | + | match.wildcards.fetch(:ether_source_address) | true | + | match.wildcards.fetch(:ether_type) | true | + | match.wildcards.fetch(:in_port) | true | + | match.wildcards.fetch(:ip_destination_address_all) | true | + | match.wildcards.fetch(:ip_protocol) | true | + | match.wildcards.fetch(:ip_source_address_all) | true | + | match.wildcards.fetch(:ip_tos) | true | + | match.wildcards.fetch(:transport_destination_port) | true | + | match.wildcards.fetch(:transport_source_port) | true | + | match.wildcards.fetch(:vlan_priority) | true | + | match.wildcards.fetch(:vlan_vid) | true | + | table_id.to_hex | 0xff | + | out_port | :none | + diff --git a/features/open_flow10/description_stats_reply.feature b/features/open_flow10/description_stats_reply.feature new file mode 100644 index 00000000..f400d0fe --- /dev/null +++ b/features/open_flow10/description_stats_reply.feature @@ -0,0 +1,18 @@ +@open_flow10 +Feature: Pio::DescriptionStats::Reply + Scenario: read + When I try to parse a file named "open_flow10/description_stats_reply.raw" with "DescriptionStats::Reply" class + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 17 | + | length | 1068 | + | transaction_id | 12 | + | xid | 12 | + | stats_type | :description | + | manufacturer | Nicira, Inc. | + | hardware | | + | software | | + | serial_number | | + | datapath | | diff --git a/features/open_flow10/desc_stats_reply.raw b/features/open_flow10/description_stats_reply.raw similarity index 100% rename from features/open_flow10/desc_stats_reply.raw rename to features/open_flow10/description_stats_reply.raw diff --git a/features/open_flow10/description_stats_request.feature b/features/open_flow10/description_stats_request.feature new file mode 100644 index 00000000..fc327638 --- /dev/null +++ b/features/open_flow10/description_stats_request.feature @@ -0,0 +1,43 @@ +@open_flow10 +Feature: Pio::DescriptionStats::Request + Scenario: new + When I try to create an OpenFlow message with: + """ + Pio::DescriptionStats::Request.new + """ + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 16 | + | length | 12 | + | transaction_id | 0 | + | xid | 0 | + | stats_type | :description | + + Scenario: new(transaction_id: 123) + When I try to create an OpenFlow message with: + """ + Pio::DescriptionStats::Request.new(transaction_id: 123) + """ + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 16 | + | length | 12 | + | transaction_id | 123 | + | xid | 123 | + | stats_type | :description | + + Scenario: read + When I try to parse a file named "open_flow10/description_stats_request.raw" with "DescriptionStats::Request" class + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 1 | + | message_type | 16 | + | length | 12 | + | transaction_id | 12 | + | xid | 12 | + | stats_type | :description | diff --git a/features/open_flow10/desc_stats_request.raw b/features/open_flow10/description_stats_request.raw similarity index 100% rename from features/open_flow10/desc_stats_request.raw rename to features/open_flow10/description_stats_request.raw diff --git a/features/open_flow10/nx_flow_mod_add.raw b/features/open_flow10/nx_flow_mod_add.raw new file mode 100644 index 00000000..4b893034 Binary files /dev/null and b/features/open_flow10/nx_flow_mod_add.raw differ diff --git a/features/open_flow10/nx_flow_mod_delete.raw b/features/open_flow10/nx_flow_mod_delete.raw new file mode 100644 index 00000000..d97cdaab Binary files /dev/null and b/features/open_flow10/nx_flow_mod_delete.raw differ diff --git a/features/open_flow10/nx_flow_mod_delete_strict.raw b/features/open_flow10/nx_flow_mod_delete_strict.raw new file mode 100644 index 00000000..0fe23cb2 Binary files /dev/null and b/features/open_flow10/nx_flow_mod_delete_strict.raw differ diff --git a/features/open_flow10/nx_flow_mod_modify.raw b/features/open_flow10/nx_flow_mod_modify.raw new file mode 100644 index 00000000..256dc20a Binary files /dev/null and b/features/open_flow10/nx_flow_mod_modify.raw differ diff --git a/features/open_flow10/nx_flow_mod_modify_strict.raw b/features/open_flow10/nx_flow_mod_modify_strict.raw new file mode 100644 index 00000000..5b67dd3c Binary files /dev/null and b/features/open_flow10/nx_flow_mod_modify_strict.raw differ diff --git a/features/open_flow13/stats_request.feature b/features/open_flow13/stats_request.feature new file mode 100644 index 00000000..24f739e0 --- /dev/null +++ b/features/open_flow13/stats_request.feature @@ -0,0 +1,19 @@ +Feature: Pio::StatsRequest + Background: + Given I use OpenFlow 1.3 + + @wip + Scenario: new + When I try to create an OpenFlow message with: + """ + Pio::StatsRequest.new(stats_type: :table) + """ + Then it should finish successfully + And the message has the following fields and values: + | field | value | + | ofp_version | 4 | + | message_type | 16 | + | message_length | 12 | + | transaction_id | 0 | + | xid | 0 | + | stats_type | :table | diff --git a/features/open_flow_read.feature b/features/open_flow_read.feature index a317f32b..32a28572 100644 --- a/features/open_flow_read.feature +++ b/features/open_flow_read.feature @@ -2,21 +2,27 @@ Feature: Pio::OpenFlow.read Scenario: OpenFlow10 Given I switch the Pio::OpenFlow version to "OpenFlow10" Then the following each raw file should be parsed into its corresponding object using OpenFlow.read - | raw file | result object | - | open_flow10/hello.raw | Pio::OpenFlow10::Hello | - | open_flow10/hello_failed.raw | Pio::OpenFlow10::Error::HelloFailed | - | open_flow13/hello_failed.raw | Pio::OpenFlow13::Error::HelloFailed | - | open_flow10/bad_request.raw | Pio::OpenFlow10::Error::BadRequest | - | open_flow13/bad_request.raw | Pio::OpenFlow13::Error::BadRequest | - | open_flow10/echo_request.raw | Pio::OpenFlow10::Echo::Request | - | open_flow10/echo_reply.raw | Pio::OpenFlow10::Echo::Reply | - | open_flow10/features_request.raw | Pio::OpenFlow10::Features::Request | - | open_flow10/features_reply.raw | Pio::OpenFlow10::Features::Reply | - | open_flow10/packet_in.raw | Pio::OpenFlow10::PacketIn | - | open_flow10/packet_out.raw | Pio::OpenFlow10::PacketOut | - | open_flow10/flow_mod_add.raw | Pio::OpenFlow10::FlowMod | - | open_flow10/port_status.raw | Pio::OpenFlow10::PortStatus | - | open_flow10/barrier_request.raw | Pio::OpenFlow10::Barrier::Request | - | open_flow10/barrier_reply.raw | Pio::OpenFlow10::Barrier::Reply | - | open_flow10/flow_stats_request.raw | Pio::OpenFlow10::FlowStats::Request | - | open_flow10/flow_stats_reply.raw | Pio::OpenFlow10::FlowStats::Reply | + | raw file | result object | + | open_flow10/aggregate_stats_reply.raw | Pio::OpenFlow10::AggregateStats::Reply | + | open_flow10/aggregate_stats_request.raw | Pio::OpenFlow10::AggregateStats::Request | + | open_flow10/bad_request.raw | Pio::OpenFlow10::Error::BadRequest | + | open_flow10/barrier_reply.raw | Pio::OpenFlow10::Barrier::Reply | + | open_flow10/barrier_request.raw | Pio::OpenFlow10::Barrier::Request | + | open_flow10/description_stats_reply.raw | Pio::OpenFlow10::DescriptionStats::Reply | + | open_flow10/description_stats_request.raw | Pio::OpenFlow10::DescriptionStats::Request | + | open_flow10/echo_reply.raw | Pio::OpenFlow10::Echo::Reply | + | open_flow10/echo_request.raw | Pio::OpenFlow10::Echo::Request | + | open_flow10/features_reply.raw | Pio::OpenFlow10::Features::Reply | + | open_flow10/features_request.raw | Pio::OpenFlow10::Features::Request | + | open_flow10/flow_mod_add.raw | Pio::OpenFlow10::FlowMod | + | open_flow10/flow_stats_reply.raw | Pio::OpenFlow10::FlowStats::Reply | + | open_flow10/flow_stats_reply.raw | Pio::OpenFlow10::FlowStats::Reply | + | open_flow10/flow_stats_request.raw | Pio::OpenFlow10::FlowStats::Request | + | open_flow10/flow_stats_request.raw | Pio::OpenFlow10::FlowStats::Request | + | open_flow10/hello.raw | Pio::OpenFlow10::Hello | + | open_flow10/hello_failed.raw | Pio::OpenFlow10::Error::HelloFailed | + | open_flow10/packet_in.raw | Pio::OpenFlow10::PacketIn | + | open_flow10/packet_out.raw | Pio::OpenFlow10::PacketOut | + | open_flow10/port_status.raw | Pio::OpenFlow10::PortStatus | + | open_flow13/bad_request.raw | Pio::OpenFlow13::Error::BadRequest | + | open_flow13/hello_failed.raw | Pio::OpenFlow13::Error::HelloFailed | diff --git a/lib/pio/arp/format.rb b/lib/pio/arp/format.rb index e514cc19..58606fcb 100644 --- a/lib/pio/arp/format.rb +++ b/lib/pio/arp/format.rb @@ -4,6 +4,7 @@ require 'pio/type/mac_address' module Pio + # ARP parser and generator. class Arp # ARP parser. class Format < BinData::Record diff --git a/lib/pio/dhcp/ack.rb b/lib/pio/dhcp/ack.rb index 03c0a9df..cb5b1995 100644 --- a/lib/pio/dhcp/ack.rb +++ b/lib/pio/dhcp/ack.rb @@ -1,6 +1,7 @@ require 'pio/dhcp/boot_reply' module Pio + # Dhcp parser and generator. class Dhcp # Dhcp Ack packet generator class Ack < BootReply diff --git a/lib/pio/icmp/format.rb b/lib/pio/icmp/format.rb index f5fedc7d..11a8d342 100644 --- a/lib/pio/icmp/format.rb +++ b/lib/pio/icmp/format.rb @@ -3,6 +3,7 @@ require 'pio/ipv4_header' module Pio + # Icmp parser and generator. class Icmp # Icmp parser. class Format < BinData::Record diff --git a/lib/pio/lldp/chassis_id_tlv.rb b/lib/pio/lldp/chassis_id_tlv.rb index 67b48a40..d878b840 100644 --- a/lib/pio/lldp/chassis_id_tlv.rb +++ b/lib/pio/lldp/chassis_id_tlv.rb @@ -1,6 +1,7 @@ require 'bindata' module Pio + # LLDP frame parser and generator. class Lldp # Chassis ID TLV class ChassisIdTlv < BinData::Primitive diff --git a/lib/pio/lldp/frame.rb b/lib/pio/lldp/frame.rb index b3e0b09f..8038a916 100644 --- a/lib/pio/lldp/frame.rb +++ b/lib/pio/lldp/frame.rb @@ -7,6 +7,7 @@ require 'pio/lldp/ttl_tlv' module Pio + # LLDP frame parser and generator. class Lldp # LLDP frame class Frame < BinData::Record diff --git a/lib/pio/open_flow.rb b/lib/pio/open_flow.rb index bd520595..222e9f70 100644 --- a/lib/pio/open_flow.rb +++ b/lib/pio/open_flow.rb @@ -17,8 +17,8 @@ def self.version def self.switch_version(version) [:Barrier, :Echo, :Features, :FlowMod, :Hello, :Match, - :PacketIn, :PacketOut, :SendOutPort, :PortStatus, - :FlowStats, :Error].each do |each| + :PacketIn, :PacketOut, :SendOutPort, :PortStatus, :Stats, + :FlowStats, :DescriptionStats, :AggregateStats, :Error].each do |each| set_message_class_name each, version @version = version.to_s end @@ -37,8 +37,8 @@ def self.read(binary) 12 => Pio::PortStatus, 13 => Pio::PacketOut, 14 => Pio::FlowMod, - 16 => Pio::FlowStats::Request, - 17 => Pio::FlowStats::Reply, + 16 => Pio::Stats::Request, + 17 => Pio::Stats::Reply, 18 => Pio::Barrier::Request, 19 => Pio::Barrier::Reply } diff --git a/lib/pio/open_flow10.rb b/lib/pio/open_flow10.rb index 1562db99..1fcb7d2d 100644 --- a/lib/pio/open_flow10.rb +++ b/lib/pio/open_flow10.rb @@ -1,5 +1,9 @@ +require 'pio/open_flow10/aggregate_stats_reply.rb' +require 'pio/open_flow10/aggregate_stats_request.rb' require 'pio/open_flow10/barrier_reply' require 'pio/open_flow10/barrier_request' +require 'pio/open_flow10/description_stats_reply' +require 'pio/open_flow10/description_stats_request' require 'pio/open_flow10/echo' require 'pio/open_flow10/error' require 'pio/open_flow10/error/bad_request' @@ -16,3 +20,5 @@ require 'pio/open_flow10/port16' require 'pio/open_flow10/port_status' require 'pio/open_flow10/send_out_port' +require 'pio/open_flow10/stats_reply' +require 'pio/open_flow10/stats_request' diff --git a/lib/pio/open_flow10/aggregate_stats_reply.rb b/lib/pio/open_flow10/aggregate_stats_reply.rb new file mode 100644 index 00000000..d17be584 --- /dev/null +++ b/lib/pio/open_flow10/aggregate_stats_reply.rb @@ -0,0 +1,38 @@ +require 'pio/open_flow10/stats_type' + +# Base module. +module Pio + # OpenFlow 1.0 messages + module OpenFlow10 + # Aggregate Stats messages + module AggregateStats + # Aggregate Stats Reply message + class Reply < OpenFlow::Message + # Message body of Flow Stats Request. + class Body < BinData::Record + endian :big + + stats_type :stats_type, value: -> { :aggregate } + uint16 :flags + uint64 :packet_count + uint64 :byte_count + uint32 :flow_count + string :padding, length: 4 + hide :padding + + def length + 24 + end + end + + # Aggregate Stats Reply message format. + class Format < BinData::Record + extend OpenFlow::Format + + header version: 1, message_type: 17 + body :body + end + end + end + end +end diff --git a/lib/pio/open_flow10/aggregate_stats_request.rb b/lib/pio/open_flow10/aggregate_stats_request.rb new file mode 100644 index 00000000..29e0a0e3 --- /dev/null +++ b/lib/pio/open_flow10/aggregate_stats_request.rb @@ -0,0 +1,42 @@ +require 'pio/open_flow10/match' +require 'pio/open_flow10/port16' +require 'pio/open_flow10/stats_type' + +# Base module. +module Pio + # OpenFlow 1.0 messages + module OpenFlow10 + # OpenFlow 1.0 Aggregate Stats messages + module AggregateStats + # OpenFlow 1.0 Aggregate Stats Request message + class Request < OpenFlow::Message + # Message body of Flow Stats Request. + class Body < BinData::Record + endian :big + + stats_type :stats_type, value: -> { :aggregate } + uint16 :flags + match10 :match + uint8 :table_id, initial_value: 0xff + string :padding, length: 1 + hide :padding + port16 :out_port, initial_value: -> { :none } + + def length + 48 + end + end + + # OpenFlow 1.0 Aggregate Stats Request message format. + class Format < BinData::Record + extend OpenFlow::Format + + header version: 1, message_type: 16 + body :body + end + + body_option :match + end + end + end +end diff --git a/lib/pio/open_flow10/description_stats_reply.rb b/lib/pio/open_flow10/description_stats_reply.rb new file mode 100644 index 00000000..faf88252 --- /dev/null +++ b/lib/pio/open_flow10/description_stats_reply.rb @@ -0,0 +1,35 @@ +require 'pio/open_flow10/stats_type' + +# Base module. +module Pio + # OpenFlow 1.0 messages + module OpenFlow10 + # OpenFlow 1.0 Description Stats messages + module DescriptionStats + # OpenFlow 1.0 Description Stats Reply message + class Reply < OpenFlow::Message + # Message body of Flow Stats Reply. + class Body < BinData::Record + endian :big + + stats_type :stats_type, value: -> { :description } + uint16 :flags + + stringz :manufacturer, length: 256 + stringz :hardware, length: 256 + stringz :software, length: 256 + stringz :serial_number, length: 32 + stringz :datapath, length: 256 + end + + # OpenFlow 1.0 Description Stats Reply message format. + class Format < BinData::Record + extend OpenFlow::Format + + header version: 1, message_type: 17 + body :body + end + end + end + end +end diff --git a/lib/pio/open_flow10/description_stats_request.rb b/lib/pio/open_flow10/description_stats_request.rb new file mode 100644 index 00000000..e1ff6965 --- /dev/null +++ b/lib/pio/open_flow10/description_stats_request.rb @@ -0,0 +1,36 @@ +require 'pio/open_flow10/stats_type' +require 'pio/open_flow/format' +require 'pio/open_flow/message' + +# Base module. +module Pio + # OpenFlow 1.0 messages + module OpenFlow10 + # OpenFlow 1.0 Description Stats messages + module DescriptionStats + # OpenFlow 1.0 Description Stats Request message + class Request < OpenFlow::Message + # Message body of Flow Stats Request. + class Body < BinData::Record + endian :big + + stats_type :stats_type, value: -> { :description } + uint16 :flags + string :body, value: '' + + def length + 4 + end + end + + # OpenFlow 1.0 Description Stats Request message format. + class Format < BinData::Record + extend OpenFlow::Format + + header version: 1, message_type: 16 + body :body + end + end + end + end +end diff --git a/lib/pio/open_flow10/error/error_type10.rb b/lib/pio/open_flow10/error/error_type10.rb index 96c242d2..b659e11d 100644 --- a/lib/pio/open_flow10/error/error_type10.rb +++ b/lib/pio/open_flow10/error/error_type10.rb @@ -1,25 +1,27 @@ module Pio module OpenFlow10 - # enum ofp_error_type - class ErrorType10 < BinData::Primitive - ERROR_TYPES = { - hello_failed: 0, - bad_request: 1, - bad_action: 2, - flow_mod_failed: 3, - port_mod_failed: 4, - queue_operation_failed: 5 - } + module Error + # enum ofp_error_type + class ErrorType10 < BinData::Primitive + ERROR_TYPES = { + hello_failed: 0, + bad_request: 1, + bad_action: 2, + flow_mod_failed: 3, + port_mod_failed: 4, + queue_operation_failed: 5 + } - endian :big - uint16 :error_type + endian :big + uint16 :error_type - def get - ERROR_TYPES.invert.fetch(error_type) - end + def get + ERROR_TYPES.invert.fetch(error_type) + end - def set(value) - self.error_type = ERROR_TYPES.fetch(value) + def set(value) + self.error_type = ERROR_TYPES.fetch(value) + end end end end diff --git a/lib/pio/open_flow10/flow_mod.rb b/lib/pio/open_flow10/flow_mod.rb index 6a5b045d..2b8e0501 100644 --- a/lib/pio/open_flow10/flow_mod.rb +++ b/lib/pio/open_flow10/flow_mod.rb @@ -40,7 +40,7 @@ class Body < BinData::Record endian :big - match_open_flow10 :match + match10 :match uint64 :cookie command :command uint16 :idle_timeout diff --git a/lib/pio/open_flow10/flow_stats_reply.rb b/lib/pio/open_flow10/flow_stats_reply.rb index 0abaade2..ee64a5cf 100644 --- a/lib/pio/open_flow10/flow_stats_reply.rb +++ b/lib/pio/open_flow10/flow_stats_reply.rb @@ -17,7 +17,7 @@ class FlowStatsEntry < BinData::Record uint8 :table_id string :padding1, length: 1 hide :padding1 - match_open_flow10 :match + match10 :match uint32 :duration_sec uint32 :duration_nsec uint16 :priority diff --git a/lib/pio/open_flow10/flow_stats_request.rb b/lib/pio/open_flow10/flow_stats_request.rb index 0ee8e34d..3defab6c 100644 --- a/lib/pio/open_flow10/flow_stats_request.rb +++ b/lib/pio/open_flow10/flow_stats_request.rb @@ -15,7 +15,7 @@ class Request < OpenFlow::Message class FlowStatsRequestBody < BinData::Record endian :big - match_open_flow10 :match + match10 :match uint8 :table_id, initial_value: 0xff string :padding, length: 1 hide :padding diff --git a/lib/pio/open_flow10/match.rb b/lib/pio/open_flow10/match.rb index ea75ea68..2fa5e1d1 100644 --- a/lib/pio/open_flow10/match.rb +++ b/lib/pio/open_flow10/match.rb @@ -163,7 +163,7 @@ def method_missing(method, *args, &block) end # Pio::MatchFormat wrapper. - class MatchOpenFlow10 < BinData::Primitive + class Match10 < BinData::Primitive endian :big string :match, diff --git a/lib/pio/open_flow10/stats_reply.rb b/lib/pio/open_flow10/stats_reply.rb new file mode 100644 index 00000000..632b5224 --- /dev/null +++ b/lib/pio/open_flow10/stats_reply.rb @@ -0,0 +1,28 @@ +module Pio + module OpenFlow10 + class Stats + # Stats reply parser. + class Reply + # Stats reply format. + class Format < BinData::Record + extend OpenFlow::Format + + header version: 1, message_type: 17 + stats_type :stats_type + end + + TYPES = { + description: OpenFlow10::DescriptionStats::Reply, + flow: OpenFlow10::FlowStats::Reply, + aggregate: OpenFlow10::AggregateStats::Reply + } + + def self.read(binary) + TYPES.fetch(Format.read(binary).stats_type.to_sym).read(binary) + rescue KeyError + raise "Unknown stats type: #{stats_type}" + end + end + end + end +end diff --git a/lib/pio/open_flow10/stats_request.rb b/lib/pio/open_flow10/stats_request.rb new file mode 100644 index 00000000..d5193737 --- /dev/null +++ b/lib/pio/open_flow10/stats_request.rb @@ -0,0 +1,28 @@ +module Pio + module OpenFlow10 + class Stats + # Stats request parser. + class Request + # Stats request format. + class Format < BinData::Record + extend OpenFlow::Format + + header version: 1, message_type: 16 + stats_type :stats_type + end + + TYPES = { + description: OpenFlow10::DescriptionStats::Request, + flow: OpenFlow10::FlowStats::Request, + aggregate: OpenFlow10::AggregateStats::Request + } + + def self.read(binary) + TYPES.fetch(Format.read(binary).stats_type.to_sym).read(binary) + rescue KeyError + raise "Unknown stats type: #{stats_type}" + end + end + end + end +end diff --git a/lib/pio/open_flow13.rb b/lib/pio/open_flow13.rb index 61e78690..5bedfdae 100644 --- a/lib/pio/open_flow13.rb +++ b/lib/pio/open_flow13.rb @@ -12,4 +12,5 @@ require 'pio/open_flow13/packet_in' require 'pio/open_flow13/packet_out' require 'pio/open_flow13/send_out_port' +require 'pio/open_flow13/stats_request' require 'pio/open_flow13/write_metadata' diff --git a/lib/pio/open_flow13/features_reply.rb b/lib/pio/open_flow13/features_reply.rb index 8ffacf1c..352ca102 100644 --- a/lib/pio/open_flow13/features_reply.rb +++ b/lib/pio/open_flow13/features_reply.rb @@ -36,6 +36,10 @@ class Body < BinData::Record capabilities :capabilities uint32 :reserved + def dpid + datapath_id + end + def length 24 end @@ -45,10 +49,6 @@ def length header version: 4, message_type: 6 body :body - - def dpid - datapath_id - end end body_option :dpid diff --git a/lib/pio/open_flow13/features_request.rb b/lib/pio/open_flow13/features_request.rb index d46380a0..91b569b1 100644 --- a/lib/pio/open_flow13/features_request.rb +++ b/lib/pio/open_flow13/features_request.rb @@ -14,10 +14,6 @@ class Format < BinData::Record header version: 4, message_type: 5 string :body, value: '' - - def user_data - body - end end end end diff --git a/lib/pio/open_flow13/meter.rb b/lib/pio/open_flow13/meter.rb index 23b8a1e0..eed315fc 100644 --- a/lib/pio/open_flow13/meter.rb +++ b/lib/pio/open_flow13/meter.rb @@ -2,7 +2,7 @@ # Base module. module Pio - # Metering + # Apply meter (rate limiter) class Meter # OpenFlow 1.3.4 OFPIT_METER instruction format class Format < BinData::Record diff --git a/lib/pio/open_flow13/stats_request.rb b/lib/pio/open_flow13/stats_request.rb new file mode 100644 index 00000000..5db8bd6a --- /dev/null +++ b/lib/pio/open_flow13/stats_request.rb @@ -0,0 +1,53 @@ +require 'pio/open_flow' + +module Pio + module OpenFlow13 + # OpenFlow 1.3 Stats Request message + class StatsRequest < OpenFlow::Message + # Request type of Stats Request message + class StatsType < BinData::Primitive + TYPES = [:description, + :flow, + :aggregate, + :table, + :port, + :queue, + :vendor] + + endian :big + + uint16 :stats_type + + def set(value) + self.stats_type = TYPES.find_index(value) + end + + def get + TYPES[stats_type] + end + end + + # OpenFlow 1.3 Stats Request message body + class Body < BinData::Record + endian :big + + stats_type :stats_type + uint16 :stats_flags + + def length + 4 + end + end + + # OpenFlow 1.3 Stats Request message format + class Format < BinData::Record + extend OpenFlow::Format + + header version: 4, message_type: 16 + body :body + end + + body_option :stats_type + end + end +end diff --git a/lib/pio/version.rb b/lib/pio/version.rb index 0e4e1117..cf016337 100644 --- a/lib/pio/version.rb +++ b/lib/pio/version.rb @@ -1,5 +1,5 @@ # Base module. module Pio # gem version. - VERSION = '0.26.0'.freeze + VERSION = '0.27.0'.freeze end