trema 0.4.5 → 0.4.6

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -4
  3. data/Guardfile +8 -0
  4. data/Rakefile +2 -1
  5. data/bin/trema +4 -0
  6. data/cruise.rb +1 -1
  7. data/features/core/switch_manager.feature +2 -2
  8. data/features/examples/message.vendor-action.feature +2 -2
  9. data/features/examples/message.vendor-stats-request.feature +20 -0
  10. data/features/trema_commands/kill.feature +4 -0
  11. data/features/trema_commands/killall.feature +1 -0
  12. data/features/trema_commands/run.feature +20 -1
  13. data/ruby/trema/command/run.rb +4 -0
  14. data/ruby/trema/default_openflow_channel_port.rb +26 -0
  15. data/ruby/trema/dsl/configuration.rb +2 -1
  16. data/ruby/trema/open-vswitch.rb +2 -4
  17. data/ruby/trema/stats-reply.c +10 -1
  18. data/ruby/trema/stats-request.c +34 -1
  19. data/ruby/trema/vendor-stats-reply.rb +6 -2
  20. data/ruby/trema/version.rb +1 -1
  21. data/spec/trema/dsl/runner_spec.rb +1 -1
  22. data/spec/trema/dsl/syntax_spec.rb +1 -1
  23. data/spec/trema/shell/vswitch_spec.rb +1 -1
  24. data/spec/trema/stats-reply_spec.rb +2 -1
  25. data/spec/trema/stats-request_spec.rb +11 -0
  26. data/src/examples/cbench_switch/cbench-switch.rb +1 -0
  27. data/src/examples/cbench_switch/cbench_switch.c +1 -1
  28. data/src/examples/openflow_message/vendor-action.rb +4 -4
  29. data/src/examples/openflow_message/vendor-stats-request.rb +66 -0
  30. data/src/examples/simple_router/arp-table.rb +6 -17
  31. data/src/examples/simple_router/interface.rb +20 -29
  32. data/src/examples/simple_router/routing-table.rb +15 -22
  33. data/src/examples/simple_router/simple-router.rb +75 -64
  34. data/src/lib/chibach.c +3 -2
  35. data/src/lib/event_handler.c +55 -23
  36. data/src/lib/event_handler.h +0 -5
  37. data/src/lib/external_callback.c +126 -0
  38. data/src/lib/external_callback.h +46 -0
  39. data/src/lib/messenger.c +58 -35
  40. data/src/lib/openflow_message.c +32 -11
  41. data/src/lib/trema.c +13 -7
  42. data/src/lib/trema.h +1 -0
  43. data/src/lib/utility.c +13 -2
  44. data/src/switch_manager/secure_channel_receiver.c +6 -1
  45. data/src/switch_manager/switch.c +27 -26
  46. data/src/switch_manager/switch_manager.c +31 -10
  47. data/src/tremashark/packet_capture.c +3 -2
  48. data/src/tremashark/tremashark.c +2 -2
  49. data/trema.gemspec +1 -1
  50. data/unittests/lib/external_callback_test.c +282 -0
  51. data/unittests/lib/messenger_test.c +22 -0
  52. data/unittests/lib/openflow_message_test.c +1 -1
  53. data/unittests/lib/trema_test.c +1 -1
  54. data/unittests/switch_manager/switch_manager_test.c +3 -3
  55. metadata +12 -6
  56. data/src/examples/simple_router/router-utils.rb +0 -211
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 56656657a56ff4e4bf6cfa8b906dfa401d954220
4
- data.tar.gz: 3cedbb6a843395235cef1387b947251913c814dc
3
+ metadata.gz: b5d236d112d0ec7ea07f28665ac7def9a03ad148
4
+ data.tar.gz: 05ee642924ce569f3c2cd3aa565a5534dae6ba30
5
5
  SHA512:
6
- metadata.gz: 03bc85f708bf3192783fa3b77e3ba6c59ddb910ba1919fa78e850cc0de36ddd80ff39c5255ea5a468a698b4663c826dece4aa877650ef80c4bff2533192083b3
7
- data.tar.gz: 5766922aab5e81eaa24ebc4fcf1e6798e094de4a48410a853b9ce3f14dcc81cf3ebd3dd25a55a2a2d868c23221c5b0c973a31369e033d1a05dcfbb4d0630bab3
6
+ metadata.gz: b3e0b32a3d66e9c29a2b0448525a377a480b0bc18c0509b5eab85c0f27ebb78c11e1886bdd31227fe0a421c9880d6abbb969f83635a8f1536be94b6ba3ac5a1f
7
+ data.tar.gz: d1ebcf9d3b41d159e30b2b778f0783500bff5d5fe41f4afa3eede21b111d134537d8ee5b7e5aa5d5f7ad6579046924ef379508407e18001bdaabad2cf7c7d1e0
data/Gemfile CHANGED
@@ -4,11 +4,7 @@ source "https://rubygems.org"
4
4
  # Include dependencies from trema.gemspec. DRY!
5
5
  gemspec
6
6
 
7
-
8
7
  # Add dependencies required to use your gem here.
9
- # Example:
10
- # gem "activesupport", ">= 2.3.5"
11
-
12
8
 
13
9
  # Add dependencies to develop your gem here.
14
10
  # Include everything needed to run rake, tests, features, etc.
@@ -24,6 +20,10 @@ group :development do
24
20
  gem "relish", "~> 0.7"
25
21
  gem "rspec", "~> 2.14.1"
26
22
  gem "yard", "~> 0.8.7.2"
23
+ gem 'guard', '~> 1.8.3' if RUBY_VERSION < '1.9.0'
24
+ gem 'guard', '~> 2.2.2' if RUBY_VERSION >= '1.9.0'
25
+ gem 'guard-bundler', '~> 1.0.0' if RUBY_VERSION < '1.9.0'
26
+ gem 'guard-bundler', '~> 2.0.0' if RUBY_VERSION >= '1.9.0'
27
27
  gem 'mime-types', '~> 1.25' if RUBY_VERSION < '1.9.0'
28
28
  gem 'mime-types', '~> 2.0' if RUBY_VERSION >= '1.9.0'
29
29
  end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :bundler do
5
+ watch('Gemfile')
6
+ # Uncomment next line if your Gemfile contains the `gemspec' command.
7
+ watch(/^.+\.gemspec/)
8
+ end
data/Rakefile CHANGED
@@ -534,7 +534,7 @@ end
534
534
 
535
535
 
536
536
  def cbench_latency_mode_options
537
- "--switches 1 --loops 10 --delay 1000"
537
+ "--port 6653 --switches 1 --loops 10 --delay 1000"
538
538
  end
539
539
 
540
540
 
@@ -784,6 +784,7 @@ def libtrema_unit_tests
784
784
  :byteorder_test => [ :log, :utility, :wrapper, :trema_wrapper ],
785
785
  :daemon_test => [ :log, :utility, :wrapper, :trema_wrapper ],
786
786
  :ether_test => [ :buffer, :log, :utility, :wrapper, :trema_wrapper ],
787
+ :external_callback_test => [],
787
788
  :messenger_test => [ :doubly_linked_list, :hash_table, :event_handler, :linked_list, :utility, :wrapper, :timer, :log, :trema_wrapper ],
788
789
  :openflow_application_interface_test => [ :buffer, :byteorder, :hash_table, :doubly_linked_list, :linked_list, :log, :openflow_message, :packet_info, :stat, :trema_wrapper, :utility, :wrapper ],
789
790
  :openflow_message_test => [ :buffer, :byteorder, :linked_list, :log, :packet_info, :utility, :wrapper, :trema_wrapper ],
data/bin/trema CHANGED
@@ -28,6 +28,7 @@ require "gli"
28
28
  require "trema/command"
29
29
  require "trema/util"
30
30
  require "trema/version"
31
+ require "trema/default_openflow_channel_port"
31
32
 
32
33
 
33
34
  class BinTrema
@@ -57,6 +58,9 @@ class BinTrema
57
58
  c.desc "Enables Trema wireshark plugin"
58
59
  c.switch [ :s, :tremashark ], :negatable => false
59
60
 
61
+ c.desc "Overrides the default openflow channel port #{Trema::DEFAULT_OPENFLOW_CHANNEL_PORT}"
62
+ c.flag [ :p, :port ]
63
+
60
64
  c.desc "Specifies emulated network configuration"
61
65
  c.flag [ :c, :conf ]
62
66
 
data/cruise.rb CHANGED
@@ -24,7 +24,7 @@
24
24
  # threshold.
25
25
  #
26
26
 
27
- $coverage_threshold = 70.0
27
+ $coverage_threshold = 70.1
28
28
 
29
29
 
30
30
  ################################################################################
@@ -14,7 +14,7 @@ Feature: switch_manager help
14
14
 
15
15
  -s, --switch=PATH the command path of switch
16
16
  -n, --name=SERVICE_NAME service name
17
- -p, --port=PORT server listen port (default 6633)
17
+ -p, --port=PORT server listen port (default 6653)
18
18
  -d, --daemonize run in the background
19
19
  -l, --logging_level=LEVEL set logging level
20
20
  -g, --syslog output log messages to syslog
@@ -32,7 +32,7 @@ Feature: switch_manager help
32
32
 
33
33
  -s, --switch=PATH the command path of switch
34
34
  -n, --name=SERVICE_NAME service name
35
- -p, --port=PORT server listen port (default 6633)
35
+ -p, --port=PORT server listen port (default 6653)
36
36
  -d, --daemonize run in the background
37
37
  -l, --logging_level=LEVEL set logging level
38
38
  -g, --syslog output log messages to syslog
@@ -11,14 +11,14 @@ Feature: "Vendor Action" sample application
11
11
  """
12
12
 
13
13
  @slow_process
14
- Scenario: Run "Packet In" C example
14
+ Scenario: Vendor Action message in C
15
15
  Given I run `trema run ../../objects/examples/openflow_message/vendor_action -c vendor_action.conf -d`
16
16
  And wait until "vendor_action" is up
17
17
  And *** sleep 2 ***
18
18
  Then the file "../../tmp/log/openflowd.vendor_action.log" should contain "actions=note:54.72.65.6d.61.00"
19
19
 
20
20
  @slow_process
21
- Scenario: Run "Packet In" Ruby example
21
+ Scenario: Vendor Action message in Ruby
22
22
  Given I run `trema run ../../src/examples/openflow_message/vendor-action.rb -c vendor_action.conf -d`
23
23
  And wait until "VendorActionSampleController" is up
24
24
  And *** sleep 2 ***
@@ -0,0 +1,20 @@
1
+ Feature: "Vendor Stats Request" sample application
2
+
3
+ In order to learn how to send Vendor Stats Request
4
+ As a developer using Trema
5
+ I want to execute "Vendor Stats Request" sample application
6
+
7
+ Background:
8
+ Given a file named "vendor_stats.conf" with:
9
+ """
10
+ vswitch( "vendor_stats" ) { datapath_id "0xabc" }
11
+ """
12
+
13
+ @slow_process
14
+ Scenario: Vendor Stats Request message in Ruby
15
+ Given I run `trema run ../../src/examples/openflow_message/vendor-stats-request.rb -c vendor_stats.conf -d`
16
+ And wait until "VendorStatsRequestSample" is up
17
+ And *** sleep 2 ***
18
+ Then the file "../../tmp/log/openflowd.vendor_stats.log" should contain "received: NXST_FLOW reques"
19
+ And the file "../../tmp/log/VendorStatsRequestSample.log" should contain "[vendor_stats_reply]"
20
+ And the file "../../tmp/log/VendorStatsRequestSample.log" should contain "vendor_id: 0x00002320"
@@ -24,22 +24,26 @@ Feature: kill command
24
24
  @slow_process
25
25
  Scenario: kill a switch
26
26
  When I run `trema kill 0x1`
27
+ And *** sleep 1 ***
27
28
  Then the vswitch "0x1" is terminated
28
29
 
29
30
  @slow_process
30
31
  Scenario: kill a host
31
32
  When I run `trema kill host1`
33
+ And *** sleep 1 ***
32
34
  Then the vhost "host1" is terminated
33
35
 
34
36
  @slow_process
35
37
  Scenario: kill hosts
36
38
  When I run `trema kill host1 host2`
39
+ And *** sleep 1 ***
37
40
  Then the vhost "host1" is terminated
38
41
  And the vhost "host2" is terminated
39
42
 
40
43
  @slow_process
41
44
  Scenario: kill a controller
42
45
  When I run `trema kill SwitchMonitor`
46
+ And *** sleep 1 ***
43
47
  Then the controller "SwitchMonitor" is terminated
44
48
 
45
49
  Scenario: no argument
@@ -23,6 +23,7 @@ Feature: killall command
23
23
  And I successfully run `trema run ../../objects/examples/switch_monitor/switch_monitor -c switch_monitor.conf -d`
24
24
  And wait until "switch_monitor" is up
25
25
  When I run `trema killall`
26
+ And *** sleep 1 ***
26
27
  Then switch_manager is terminated
27
28
  And switch is terminated
28
29
  And phost is terminated
@@ -23,13 +23,32 @@ Feature: run command
23
23
  And wait until "learning_switch" is up
24
24
  Then the output should contain:
25
25
  """
26
- switch_manager --daemonize --port=6633 -- port_status::learning_switch packet_in::learning_switch state_notify::learning_switch vendor::learning_switch
26
+ switch_manager --daemonize --port=6653 -- port_status::learning_switch packet_in::learning_switch state_notify::learning_switch vendor::learning_switch
27
27
  """
28
28
  And the output should contain:
29
29
  """
30
30
  learning_switch --name learning_switch -d
31
31
  """
32
32
 
33
+ @slow_process
34
+ Scenario: The --port option can override the default openflow channel port
35
+ When I run `which trema`
36
+ When I run `trema -v run ../../objects/examples/learning_switch/learning_switch -c network.conf --port 6633 -d`
37
+ And wait until "learning_switch" is up
38
+ Then the output should contain:
39
+ """
40
+ switch_manager --daemonize --port=6633 -- port_status::learning_switch packet_in::learning_switch state_notify::learning_switch vendor::learning_switch
41
+ """
42
+
43
+ @slow_process
44
+ Scenario: The -p option can override the default openflow channel port
45
+ When I run `trema -v run ../../objects/examples/learning_switch/learning_switch -c network.conf -p 6633 -d`
46
+ And wait until "learning_switch" is up
47
+ Then the output should contain:
48
+ """
49
+ switch_manager --daemonize --port=6633 -- port_status::learning_switch packet_in::learning_switch state_notify::learning_switch vendor::learning_switch
50
+ """
51
+
33
52
  @slow_process
34
53
  Scenario: switch_manager is killed when trema session is closed
35
54
  When I run `trema -v run /bin/true -c network.conf`
@@ -16,6 +16,7 @@
16
16
  #
17
17
 
18
18
 
19
+ require "trema/default_openflow_channel_port"
19
20
  require "trema/dsl"
20
21
  require "trema/util"
21
22
 
@@ -27,6 +28,7 @@ module Trema
27
28
 
28
29
  def trema_run options
29
30
  @config_file = options[ :conf ] || nil
31
+ @openflow_port = options[ :port ] || DEFAULT_OPENFLOW_CHANNEL_PORT
30
32
 
31
33
  if options[ :daemonize ]
32
34
  $run_as_daemon = true
@@ -71,6 +73,8 @@ module Trema
71
73
  config = Trema::DSL::Configuration.new
72
74
  end
73
75
 
76
+ config.port = @openflow_port
77
+
74
78
  if ARGV[ 0 ]
75
79
  controller_file = ARGV[ 0 ].split.first
76
80
  if ruby_controller?
@@ -0,0 +1,26 @@
1
+ #
2
+ # Copyright (C) 2008-2013 NEC Corporation
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License, version 2, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along
14
+ # with this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
+ #
17
+
18
+ module Trema
19
+ DEFAULT_OPENFLOW_CHANNEL_PORT = 6653
20
+ end
21
+
22
+ ### Local variables:
23
+ ### mode: Ruby
24
+ ### coding: utf-8
25
+ ### indent-tabs-mode: nil
26
+ ### End:
@@ -16,6 +16,7 @@
16
16
  #
17
17
 
18
18
 
19
+ require "trema/default_openflow_channel_port"
19
20
  require "trema/app"
20
21
  require "trema/host"
21
22
  require "trema/link"
@@ -97,7 +98,7 @@ module Trema
97
98
  # @return [Configuration]
98
99
  #
99
100
  def initialize
100
- @port = 6633
101
+ @port = DEFAULT_OPENFLOW_CHANNEL_PORT
101
102
  @apps = Trema::App.clear
102
103
  @hosts = Trema::Host.clear
103
104
  @links = Trema::Link.clear
@@ -16,6 +16,7 @@
16
16
  #
17
17
 
18
18
 
19
+ require "trema/default_openflow_channel_port"
19
20
  require "trema/daemon"
20
21
  require "trema/executables"
21
22
  require "trema/hardware-switch"
@@ -31,9 +32,6 @@ module Trema
31
32
  include Trema::Daemon
32
33
 
33
34
 
34
- DEFAULT_PORT = 6633
35
-
36
-
37
35
  log_file { | vswitch | "openflowd.#{ vswitch.name }.log" }
38
36
  command { | vswitch | vswitch.__send__ :command }
39
37
 
@@ -46,7 +44,7 @@ module Trema
46
44
  #
47
45
  # @return [OpenVswitch]
48
46
  #
49
- def initialize stanza, port = DEFAULT_PORT
47
+ def initialize stanza, port = DEFAULT_OPENFLOW_CHANNEL_PORT
50
48
  super stanza
51
49
  @port = port
52
50
  @interfaces = []
@@ -502,12 +502,21 @@ handle_stats_reply(
502
502
  case OFPST_VENDOR:
503
503
  {
504
504
  uint32_t *vendor_id;
505
- VALUE options = rb_hash_new();
506
505
  VALUE vendor_stats_arr = rb_ary_new2( 1 );
506
+ VALUE options = rb_hash_new();
507
507
  VALUE vendor_stats_reply;
508
508
 
509
509
  vendor_id = ( uint32_t * ) body->data;
510
510
  rb_hash_aset( options, ID2SYM( rb_intern( "vendor_id" ) ), UINT2NUM( *vendor_id ) );
511
+ if ( body_length > sizeof( uint32_t ) ) {
512
+ unsigned long length = body_length - sizeof( uint32_t );
513
+ uint8_t *data = ( uint8_t * ) body->data + sizeof( uint32_t );
514
+ VALUE ary = rb_ary_new2( ( signed ) length );
515
+ for ( unsigned long i = 0; i < length; i++ ) {
516
+ rb_ary_push( ary, INT2FIX( data[ i ] ) );
517
+ }
518
+ rb_hash_aset( options, ID2SYM( rb_intern( "data" ) ), ary );
519
+ }
511
520
  vendor_stats_reply = rb_funcall( rb_eval_string( "Trema::VendorStatsReply" ), rb_intern( "new" ), 1, options );
512
521
  rb_ary_push( vendor_stats_arr, vendor_stats_reply );
513
522
 
@@ -17,6 +17,7 @@
17
17
 
18
18
 
19
19
  #include "trema.h"
20
+ #include "trema-ruby-utils.h"
20
21
  #include "ruby.h"
21
22
 
22
23
 
@@ -262,6 +263,18 @@ stats_vendor_id( VALUE self ) {
262
263
  }
263
264
 
264
265
 
266
+ /*
267
+ * Vendor specific data payload.
268
+ *
269
+ * @return [Array] an array of data payload bytes.
270
+ * @return [nil] vendor specific data not found.
271
+ */
272
+ static VALUE
273
+ stats_vendor_data( VALUE self ) {
274
+ return rb_iv_get( self, "@data" );
275
+ }
276
+
277
+
265
278
  uint32_t
266
279
  get_stats_request_num2uint( VALUE self, const char *field ) {
267
280
  return ( uint32_t ) NUM2UINT( rb_iv_get( self, field ) );
@@ -575,7 +588,10 @@ queue_stats_request_init( int argc, VALUE *argv, VALUE self ) {
575
588
  *
576
589
  * @example
577
590
  * VendorStatsRequest.new
578
- * VendorStatsRequest.new( :vendor_id => 123 )
591
+ * VendorStatsRequest.new(
592
+ * :vendor_id => 123,
593
+ * :data => "deadbeef".unpack( "C*" )
594
+ * )
579
595
  *
580
596
  * @param [Hash] options
581
597
  * the options to create a message with.
@@ -584,6 +600,9 @@ queue_stats_request_init( int argc, VALUE *argv, VALUE self ) {
584
600
  * request statistics for a specific vendor_id, otherwise set vendor_id
585
601
  * to a default value of 0x00004cff.
586
602
  *
603
+ * @option options [Array] :data
604
+ * a String that holds vendor's defined arbitrary length data.
605
+ *
587
606
  * @return [VendorStatsRequest]
588
607
  * an object that encapsulates the +OFPT_STATS_REQUEST(OFPST_VENDOR)+ OpenFlow
589
608
  * message.
@@ -610,6 +629,19 @@ vendor_stats_request_init( int argc, VALUE *argv, VALUE self ) {
610
629
  uint32_t *vendor;
611
630
  vendor = ( uint32_t * ) stats_request->body;
612
631
  *vendor = htonl( get_stats_request_num2uint( self, "@vendor_id" ) );
632
+
633
+ VALUE ary = rb_hash_aref( options, ID2SYM( rb_intern( "data" ) ) );
634
+ message->length = offsetof( struct ofp_stats_request, body ) + sizeof( uint32_t );
635
+ if ( ary != Qnil ) {
636
+ rb_iv_set( self, "@data", ary );
637
+ Check_Type( ary, T_ARRAY );
638
+ uint16_t ary_len = ( uint16_t ) RARRAY_LEN( ary );
639
+ uint8_t *data = append_back_buffer( message, ary_len );
640
+ for ( int i = 0; i < ary_len; i++ ) {
641
+ data[ i ] = ( uint8_t ) FIX2INT( RARRAY_PTR( ary )[ i ] );
642
+ }
643
+ }
644
+ set_length( message, ( uint16_t ) message->length );
613
645
  return self;
614
646
  }
615
647
 
@@ -671,6 +703,7 @@ Init_stats_request() {
671
703
  rb_define_alloc_func( cVendorStatsRequest, vendor_stats_request_alloc );
672
704
  rb_define_method( cVendorStatsRequest, "initialize", vendor_stats_request_init, -1 );
673
705
  rb_define_method( cVendorStatsRequest, "vendor_id", stats_vendor_id, 0 );
706
+ rb_define_method( cVendorStatsRequest, "data", stats_vendor_data, 0 );
674
707
  }
675
708
 
676
709
 
@@ -21,7 +21,7 @@ require "trema/stats-helper"
21
21
 
22
22
  module Trema
23
23
  class VendorStatsReply < StatsHelper
24
- FIELDS = %w(vendor_id)
24
+ FIELDS = %w(vendor_id data)
25
25
  FIELDS.each { |field| attr_reader field.intern }
26
26
 
27
27
 
@@ -34,7 +34,8 @@ module Trema
34
34
  #
35
35
  # @example
36
36
  # VendorStatsReply.new(
37
- # :vendor_id => 123
37
+ # :vendor_id => 123,
38
+ # :data => "deadbeef".unpack( "C*" )
38
39
  # )
39
40
  #
40
41
  # @param [Hash] options
@@ -43,6 +44,9 @@ module Trema
43
44
  # @option options [Number] :vendor_id
44
45
  # the specific vendor identifier.
45
46
  #
47
+ # @option options [Array] :data
48
+ # a String that holds vendor's defined arbitrary length data.
49
+ #
46
50
  # @return [VendorStatsReply]
47
51
  # an object that encapsulates the OFPST_STATS_REPLY(OFPST_VENDOR) OpenFlow message.
48
52
  #