trema 0.2.2.1 → 0.2.3
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.
- data/.gitmodules +3 -0
- data/.travis.yml +13 -0
- data/.yardopts +4 -0
- data/Gemfile +2 -3
- data/README.md +43 -97
- data/Rakefile +60 -4
- data/Rantfile +11 -10
- data/cruise.rb +4 -6
- data/features/example.packetin_filter_config.feature +10 -10
- data/features/example.switch_monitor.feature +14 -2
- data/features/step_definitions/kill_steps.rb +2 -2
- data/features/step_definitions/{off_steps.rb → killall_steps.rb} +2 -2
- data/features/step_definitions/misc_steps.rb +1 -1
- data/features/step_definitions/up_steps.rb +30 -0
- data/features/trema.feature +1 -0
- data/features/trema.run.feature +1 -0
- data/locale/README.ja.md +19 -0
- data/locale/ja/yard.po +3762 -0
- data/locale/yard.pot +3740 -0
- data/ruby/extconf.rb +4 -1
- data/ruby/trema/action-common.c +3 -17
- data/ruby/trema/action-common.h +3 -7
- data/ruby/trema/action.rb +33 -0
- data/ruby/trema/app.rb +1 -1
- data/ruby/trema/barrier-request.c +1 -0
- data/ruby/trema/command/run.rb +13 -9
- data/ruby/trema/command/usage.rb +1 -0
- data/ruby/trema/command/version.rb +1 -1
- data/ruby/trema/controller.c +133 -50
- data/ruby/trema/controller.rb +2 -2
- data/ruby/trema/desc-stats-reply.rb +77 -0
- data/ruby/trema/dsl/configuration.rb +3 -14
- data/ruby/trema/dsl/rswitch.rb +47 -0
- data/ruby/trema/dsl/runner.rb +4 -1
- data/ruby/trema/dsl/syntax.rb +11 -8
- data/ruby/trema/echo-reply.c +59 -45
- data/ruby/trema/echo-reply.h +1 -3
- data/ruby/trema/echo-request.c +49 -71
- data/ruby/trema/echo-request.h +0 -2
- data/ruby/trema/echo.c +99 -0
- data/ruby/trema/{action-enqueue.h → echo.h} +6 -7
- data/ruby/trema/enqueue.rb +87 -0
- data/ruby/trema/error.c +109 -104
- data/ruby/trema/error.h +0 -2
- data/ruby/trema/features-reply.c +89 -35
- data/ruby/trema/features-reply.h +0 -6
- data/ruby/trema/features-request.c +63 -37
- data/ruby/trema/features-request.h +0 -2
- data/ruby/trema/flow-mod.c +149 -0
- data/ruby/trema/{action-output.h → flow-mod.h} +6 -6
- data/ruby/trema/get-config-request.c +1 -0
- data/ruby/trema/hardware-switch.rb +88 -0
- data/ruby/trema/hello.c +55 -31
- data/ruby/trema/hello.h +0 -2
- data/ruby/trema/ip.rb +12 -2
- data/ruby/trema/logger.rb +29 -0
- data/ruby/trema/mac.rb +57 -36
- data/ruby/trema/match.c +7 -9
- data/ruby/trema/monkey-patch/integer/ranges.rb +0 -2
- data/ruby/trema/network-component.rb +1 -1
- data/ruby/trema/open-vswitch.rb +2 -2
- data/ruby/trema/openflow-switch.rb +3 -54
- data/ruby/trema/{packet_in.c → packet-in.c} +262 -175
- data/ruby/trema/{packet_in.h → packet-in.h} +0 -2
- data/ruby/trema/packet-queue.rb +4 -3
- data/ruby/trema/port-mod.c +8 -9
- data/ruby/trema/port-status-add.rb +60 -0
- data/ruby/trema/port-status-delete.rb +60 -0
- data/ruby/trema/port-status-modify.rb +60 -0
- data/ruby/trema/port-status.c +48 -15
- data/ruby/trema/port-status.h +6 -8
- data/ruby/trema/port.c +63 -8
- data/ruby/trema/queue-get-config-request.c +1 -0
- data/ruby/trema/ruby-switch.rb +62 -0
- data/ruby/trema/send-out-port.rb +97 -0
- data/ruby/trema/set-config.c +1 -0
- data/ruby/trema/set-eth-addr.rb +45 -0
- data/ruby/trema/set-eth-dst-addr.rb +54 -0
- data/ruby/trema/set-eth-src-addr.rb +54 -0
- data/ruby/trema/set-ip-addr.rb +47 -0
- data/ruby/trema/set-ip-dst-addr.rb +53 -0
- data/ruby/trema/set-ip-src-addr.rb +52 -0
- data/ruby/trema/set-ip-tos.rb +63 -0
- data/ruby/trema/set-transport-dst-port.rb +53 -0
- data/ruby/trema/set-transport-port.rb +52 -0
- data/ruby/trema/set-transport-src-port.rb +54 -0
- data/ruby/trema/set-vlan-priority.rb +65 -0
- data/ruby/trema/set-vlan-vid.rb +64 -0
- data/ruby/trema/shell/down.rb +1 -1
- data/ruby/trema/shell/link.rb +4 -4
- data/ruby/trema/shell/run.rb +8 -6
- data/ruby/trema/shell/up.rb +3 -3
- data/ruby/trema/stats-reply.c +27 -2
- data/ruby/trema/stats-request.c +64 -23
- data/ruby/trema/strip-vlan-header.rb +41 -0
- data/ruby/trema/switch.c +196 -0
- data/ruby/trema/{action-vendor.h → switch.h} +5 -7
- data/ruby/trema/switch.rb +28 -9
- data/ruby/trema/trema-ruby-utils.c +66 -0
- data/ruby/trema/{action-set-dl-src.h → trema-ruby-utils.h} +9 -11
- data/ruby/trema/trema.c +61 -61
- data/ruby/trema/vendor-action.rb +73 -0
- data/ruby/trema/vendor.c +121 -52
- data/ruby/trema/vendor.h +6 -10
- data/ruby/trema/version.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/action.rb +52 -0
- data/spec/support/mandatory-option.rb +56 -0
- data/spec/support/openflow-message.rb +91 -7
- data/spec/support/port-status.rb +38 -0
- data/spec/trema/controller_spec.rb +0 -26
- data/spec/trema/dsl/configuration_spec.rb +3 -3
- data/spec/trema/dsl/runner_spec.rb +12 -32
- data/spec/trema/dsl/syntax_spec.rb +2 -11
- data/spec/trema/echo-reply_spec.rb +49 -14
- data/spec/trema/echo-request_spec.rb +86 -34
- data/spec/trema/enqueue_spec.rb +76 -0
- data/spec/trema/error_spec.rb +43 -58
- data/spec/trema/features-reply_spec.rb +58 -24
- data/spec/trema/features-request_spec.rb +54 -28
- data/spec/trema/flow-mod_spec.rb +99 -0
- data/spec/trema/{openflow-switch_spec.rb → hardware-switch_spec.rb} +3 -3
- data/spec/trema/hello_spec.rb +28 -14
- data/spec/trema/ip_spec.rb +54 -0
- data/spec/trema/mac_spec.rb +49 -64
- data/spec/trema/match_spec.rb +1 -1
- data/spec/trema/open-vswitch_spec.rb +7 -7
- data/spec/trema/packet-in_spec.rb +73 -16
- data/spec/trema/port-status-add_spec.rb +32 -0
- data/spec/trema/port-status-delete_spec.rb +32 -0
- data/spec/trema/port-status-modify_spec.rb +71 -0
- data/spec/trema/port-status_spec.rb +5 -76
- data/spec/trema/{action-output_spec.rb → send-out-port_spec.rb} +20 -47
- data/spec/trema/set-eth-dst-addr_spec.rb +75 -0
- data/spec/trema/set-eth-src-addr_spec.rb +72 -0
- data/spec/trema/set-ip-dst-addr_spec.rb +58 -0
- data/spec/trema/set-ip-src-addr_spec.rb +58 -0
- data/spec/trema/set-ip-tos_spec.rb +65 -0
- data/spec/trema/set-transport-dst-port_spec.rb +65 -0
- data/spec/trema/set-transport-src-port_spec.rb +65 -0
- data/spec/trema/set-vlan-priority_spec.rb +65 -0
- data/spec/trema/set-vlan-vid_spec.rb +65 -0
- data/spec/trema/shell/vhost_spec.rb +4 -1
- data/spec/trema/shell/vswitch_spec.rb +11 -11
- data/spec/trema/stats-reply_spec.rb +59 -13
- data/spec/trema/stats-request_spec.rb +6 -0
- data/spec/trema/{action-strip-vlan_spec.rb → strip-vlan-header_spec.rb} +3 -17
- data/spec/trema/switch-daemon_spec.rb +39 -0
- data/spec/trema/vendor-action_spec.rb +81 -0
- data/spec/trema/vendor_spec.rb +76 -0
- data/spec/trema_spec.rb +56 -0
- data/src/examples/dumper/dumper.c +0 -8
- data/src/examples/dumper/dumper.rb +52 -52
- data/src/examples/hello_trema/hello_trema.c +0 -2
- data/src/examples/learning_switch/learning-switch.rb +3 -3
- data/src/examples/multi_learning_switch/multi-learning-switch.rb +3 -3
- data/src/examples/openflow_message/features-request.rb +3 -3
- data/src/examples/packetin_filter_config/utils.c +4 -4
- data/src/examples/repeater_hub/repeater-hub.rb +3 -3
- data/src/examples/switch_info/switch_info.rb +2 -2
- data/src/examples/switch_monitor/switch_monitor.c +1 -1
- data/src/examples/traffic_monitor/traffic-monitor.rb +3 -3
- data/src/lib/arp.h +4 -1
- data/src/lib/chibach.c +391 -0
- data/src/lib/chibach.h +71 -0
- data/src/lib/chibach_private.c +170 -0
- data/src/lib/chibach_private.h +52 -0
- data/src/lib/ether.c +2 -1
- data/src/lib/ether.h +0 -1
- data/src/lib/ipv4.h +13 -14
- data/{ruby/trema/action-set-nw-src.h → src/lib/ipv6.h} +13 -9
- data/src/lib/log.c +161 -58
- data/src/lib/log.h +11 -16
- data/src/lib/messenger.c +36 -1
- data/src/lib/messenger.h +1 -0
- data/src/lib/openflow_application_interface.c +128 -28
- data/src/lib/openflow_application_interface.h +31 -6
- data/src/lib/openflow_message.c +2 -1
- data/src/lib/openflow_service_interface.h +1 -0
- data/src/lib/openflow_switch_interface.c +1380 -0
- data/src/lib/openflow_switch_interface.h +264 -0
- data/src/lib/packet_info.c +94 -11
- data/src/lib/packet_info.h +22 -3
- data/src/lib/packet_parser.c +38 -2
- data/src/lib/secure_channel.c +498 -0
- data/{ruby/trema/vendor-request.h → src/lib/secure_channel.h} +11 -10
- data/src/lib/tcp.h +0 -3
- data/src/lib/trema.c +38 -5
- data/{ruby/trema/action-set-nw-dst.h → src/lib/trema.hpp} +17 -8
- data/src/lib/trema_wrapper.c +5 -0
- data/src/lib/trema_wrapper.h +4 -0
- data/src/lib/utility.c +93 -4
- data/src/lib/utility.h +1 -0
- data/src/lib/wrapper.c +30 -7
- data/src/lib/wrapper.h +2 -0
- data/src/switch_manager/ofpmsg_recv.c +44 -30
- data/src/switch_manager/ofpmsg_send.c +40 -1
- data/src/switch_manager/ofpmsg_send.h +2 -0
- data/src/switch_manager/switch.c +153 -8
- data/src/switch_manager/switch.h +1 -0
- data/src/switch_manager/switchinfo.h +5 -0
- data/src/tremashark/README +2 -2
- data/src/tremashark/plugin/packet-trema/packet-trema.c +1 -0
- data/trema +1 -1
- data/unittests/lib/log_test.c +158 -34
- data/unittests/lib/openflow_application_interface_test.c +252 -69
- data/unittests/lib/openflow_message_test.c +3 -1
- data/unittests/lib/packet_parser_test.c +60 -15
- data/unittests/lib/test_packets/icmp6_echo_rep.cap +0 -0
- data/unittests/lib/test_packets/icmp6_echo_req.cap +0 -0
- data/unittests/lib/trema_test.c +2 -0
- data/unittests/lib/utility_test.c +65 -2
- data/unittests/lib/wrapper_test.c +29 -0
- data/vendor/{README → README.md} +2 -12
- data/vendor/packet-openflow.diff +13 -0
- metadata +86 -53
- data/GPL2 +0 -339
- data/ruby/trema/action-enqueue.c +0 -161
- data/ruby/trema/action-output.c +0 -169
- data/ruby/trema/action-set-dl-dst.c +0 -131
- data/ruby/trema/action-set-dl-dst.h +0 -44
- data/ruby/trema/action-set-dl-src.c +0 -131
- data/ruby/trema/action-set-nw-dst.c +0 -135
- data/ruby/trema/action-set-nw-src.c +0 -140
- data/ruby/trema/action-set-nw-tos.c +0 -124
- data/ruby/trema/action-set-nw-tos.h +0 -42
- data/ruby/trema/action-set-tp-dst.c +0 -122
- data/ruby/trema/action-set-tp-dst.h +0 -42
- data/ruby/trema/action-set-tp-src.c +0 -124
- data/ruby/trema/action-set-tp-src.h +0 -42
- data/ruby/trema/action-set-vlan-pcp.c +0 -128
- data/ruby/trema/action-set-vlan-pcp.h +0 -42
- data/ruby/trema/action-set-vlan-vid.c +0 -125
- data/ruby/trema/action-set-vlan-vid.h +0 -42
- data/ruby/trema/action-strip-vlan.c +0 -81
- data/ruby/trema/action-strip-vlan.h +0 -42
- data/ruby/trema/action-vendor.c +0 -121
- data/ruby/trema/vendor-request.c +0 -193
- data/spec/trema/action-enqueue_spec.rb +0 -100
- data/spec/trema/action-set-dl-dst_spec.rb +0 -95
- data/spec/trema/action-set-dl-src_spec.rb +0 -92
- data/spec/trema/action-set-nw-dst_spec.rb +0 -96
- data/spec/trema/action-set-nw-src_spec.rb +0 -97
- data/spec/trema/action-set-nw-tos_spec.rb +0 -88
- data/spec/trema/action-set-tp-dst_spec.rb +0 -88
- data/spec/trema/action-set-tp-src_spec.rb +0 -88
- data/spec/trema/action-set-vlan-pcp_spec.rb +0 -91
- data/spec/trema/action-set-vlan-vid_spec.rb +0 -91
- data/spec/trema/action-vendor_spec.rb +0 -90
- data/spec/trema/vendor-request_spec.rb +0 -79
|
@@ -0,0 +1,1380 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Author: Yasunobu Chiba
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2008-2012 NEC Corporation
|
|
5
|
+
*
|
|
6
|
+
* This program is free software; you can redistribute it and/or modify
|
|
7
|
+
* it under the terms of the GNU General Public License, version 2, as
|
|
8
|
+
* published by the Free Software Foundation.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU General Public License along
|
|
16
|
+
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
17
|
+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
#include <assert.h>
|
|
22
|
+
#include <inttypes.h>
|
|
23
|
+
#include <arpa/inet.h>
|
|
24
|
+
#include <syslog.h>
|
|
25
|
+
#include "chibach_private.h"
|
|
26
|
+
#include "hash_table.h"
|
|
27
|
+
#include "log.h"
|
|
28
|
+
#include "messenger.h"
|
|
29
|
+
#include "openflow_message.h"
|
|
30
|
+
#include "openflow_service_interface.h"
|
|
31
|
+
#include "openflow_switch_interface.h"
|
|
32
|
+
#include "secure_channel.h"
|
|
33
|
+
#include "timer.h"
|
|
34
|
+
#include "wrapper.h"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
typedef struct {
|
|
38
|
+
uint64_t datapath_id;
|
|
39
|
+
struct {
|
|
40
|
+
uint32_t ip;
|
|
41
|
+
uint16_t port;
|
|
42
|
+
} controller;
|
|
43
|
+
} openflow_switch_config;
|
|
44
|
+
|
|
45
|
+
typedef bool ( *message_send_handler )( buffer *message, void *user_data );
|
|
46
|
+
|
|
47
|
+
typedef struct {
|
|
48
|
+
uint32_t transaction_id;
|
|
49
|
+
buffer *message;
|
|
50
|
+
message_send_handler send_callback;
|
|
51
|
+
void *user_data;
|
|
52
|
+
time_t created_at;
|
|
53
|
+
} openflow_context;
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
static bool openflow_switch_interface_initialized = false;
|
|
57
|
+
static openflow_event_handlers event_handlers;
|
|
58
|
+
static openflow_switch_config config;
|
|
59
|
+
static const int CONTEXT_LIFETIME = 5;
|
|
60
|
+
static hash_table *contexts = NULL;
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
static bool
|
|
64
|
+
compare_context( const void *x, const void *y ) {
|
|
65
|
+
const openflow_context *cx = x;
|
|
66
|
+
const openflow_context *cy = y;
|
|
67
|
+
|
|
68
|
+
return ( cx->transaction_id == cy->transaction_id ) ? true : false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
static unsigned int
|
|
73
|
+
hash_context( const void *key ) {
|
|
74
|
+
return ( unsigned int ) *( ( const uint32_t * ) key );
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
static openflow_context *
|
|
79
|
+
lookup_context( uint32_t transaction_id ) {
|
|
80
|
+
assert( contexts != NULL );
|
|
81
|
+
|
|
82
|
+
return lookup_hash_entry( contexts, &transaction_id );
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
static bool
|
|
87
|
+
save_context( uint32_t transaction_id, buffer *message, message_send_handler callback, void *user_data ) {
|
|
88
|
+
assert( contexts != NULL );
|
|
89
|
+
|
|
90
|
+
openflow_context *context = lookup_context( transaction_id );
|
|
91
|
+
if ( context != NULL ) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
context = xmalloc( sizeof( openflow_context ) );
|
|
96
|
+
memset( context, 0, sizeof( openflow_context ) );
|
|
97
|
+
context->transaction_id = transaction_id;
|
|
98
|
+
context->message = duplicate_buffer( message );
|
|
99
|
+
context->send_callback = callback;
|
|
100
|
+
context->user_data = user_data;
|
|
101
|
+
context->created_at = time( NULL );
|
|
102
|
+
|
|
103
|
+
insert_hash_entry( contexts, &context->transaction_id, context );
|
|
104
|
+
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
static void
|
|
110
|
+
delete_context( uint32_t transaction_id ) {
|
|
111
|
+
assert( contexts != NULL );
|
|
112
|
+
|
|
113
|
+
openflow_context *context = delete_hash_entry( contexts, &transaction_id );
|
|
114
|
+
if ( context == NULL ) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if ( context->message != NULL ) {
|
|
119
|
+
free_buffer( context->message );
|
|
120
|
+
}
|
|
121
|
+
if ( context->user_data != NULL ) {
|
|
122
|
+
xfree( context->user_data );
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
xfree( context );
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
static void
|
|
130
|
+
age_contexts( void *user_data ) {
|
|
131
|
+
UNUSED( user_data );
|
|
132
|
+
|
|
133
|
+
time_t now = time( NULL );
|
|
134
|
+
|
|
135
|
+
hash_iterator iter;
|
|
136
|
+
init_hash_iterator( contexts, &iter );
|
|
137
|
+
hash_entry *e = NULL;
|
|
138
|
+
while ( ( e = iterate_hash_next( &iter ) ) != NULL ) {
|
|
139
|
+
openflow_context *context = e->value;
|
|
140
|
+
if ( ( context != NULL ) && ( ( context->created_at + CONTEXT_LIFETIME ) <= now ) ) {
|
|
141
|
+
delete_context( context->transaction_id );
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
static void
|
|
148
|
+
init_context() {
|
|
149
|
+
assert( contexts == NULL );
|
|
150
|
+
|
|
151
|
+
contexts = create_hash_with_size( compare_context, hash_context, 16 );
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
static void
|
|
156
|
+
finalize_context() {
|
|
157
|
+
assert( contexts != NULL );
|
|
158
|
+
|
|
159
|
+
hash_iterator iter;
|
|
160
|
+
init_hash_iterator( contexts, &iter );
|
|
161
|
+
hash_entry *e = NULL;
|
|
162
|
+
while ( ( e = iterate_hash_next( &iter ) ) != NULL ) {
|
|
163
|
+
openflow_context *context = e->value;
|
|
164
|
+
if ( context != NULL ) {
|
|
165
|
+
delete_context( context->transaction_id );
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
delete_hash( contexts );
|
|
169
|
+
contexts = NULL;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
bool
|
|
174
|
+
openflow_switch_interface_is_initialized() {
|
|
175
|
+
return openflow_switch_interface_initialized;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
bool
|
|
180
|
+
switch_set_openflow_event_handlers( const openflow_event_handlers handlers ) {
|
|
181
|
+
assert( openflow_switch_interface_initialized );
|
|
182
|
+
|
|
183
|
+
memcpy( &event_handlers, &handlers, sizeof( event_handlers ) );
|
|
184
|
+
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
bool
|
|
190
|
+
set_controller_connected_handler( controller_connected_handler callback, void *user_data ) {
|
|
191
|
+
assert( callback != NULL );
|
|
192
|
+
assert( openflow_switch_interface_initialized );
|
|
193
|
+
|
|
194
|
+
debug( "Setting a controller connected handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
195
|
+
|
|
196
|
+
event_handlers.controller_connected_callback = callback;
|
|
197
|
+
event_handlers.controller_connected_user_data = user_data;
|
|
198
|
+
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
bool
|
|
204
|
+
set_controller_disconnected_handler( controller_disconnected_handler callback, void *user_data ) {
|
|
205
|
+
assert( callback != NULL );
|
|
206
|
+
assert( openflow_switch_interface_initialized );
|
|
207
|
+
|
|
208
|
+
debug( "Setting a controller disconnected handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
209
|
+
|
|
210
|
+
event_handlers.controller_disconnected_callback = callback;
|
|
211
|
+
event_handlers.controller_disconnected_user_data = user_data;
|
|
212
|
+
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
bool
|
|
218
|
+
set_hello_handler( hello_handler callback, void *user_data ) {
|
|
219
|
+
assert( callback != NULL );
|
|
220
|
+
assert( openflow_switch_interface_initialized );
|
|
221
|
+
|
|
222
|
+
debug( "Setting a hello handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
223
|
+
|
|
224
|
+
event_handlers.hello_callback = callback;
|
|
225
|
+
event_handlers.hello_user_data = user_data;
|
|
226
|
+
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
bool
|
|
232
|
+
switch_set_error_handler( error_handler callback, void *user_data ) {
|
|
233
|
+
assert( callback != NULL );
|
|
234
|
+
assert( openflow_switch_interface_initialized );
|
|
235
|
+
|
|
236
|
+
debug( "Setting an error handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
237
|
+
|
|
238
|
+
event_handlers.error_callback = callback;
|
|
239
|
+
event_handlers.error_user_data = user_data;
|
|
240
|
+
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
bool
|
|
246
|
+
set_echo_request_handler( echo_request_handler callback, void *user_data ) {
|
|
247
|
+
assert( callback != NULL );
|
|
248
|
+
assert( openflow_switch_interface_initialized );
|
|
249
|
+
|
|
250
|
+
debug( "Setting an echo request handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
251
|
+
|
|
252
|
+
event_handlers.echo_request_callback = callback;
|
|
253
|
+
event_handlers.echo_request_user_data = user_data;
|
|
254
|
+
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
bool
|
|
260
|
+
switch_set_echo_reply_handler( echo_reply_handler callback, void *user_data ) {
|
|
261
|
+
assert( callback != NULL );
|
|
262
|
+
assert( openflow_switch_interface_initialized );
|
|
263
|
+
|
|
264
|
+
debug( "Setting an echo reply handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
265
|
+
|
|
266
|
+
event_handlers.echo_reply_callback = callback;
|
|
267
|
+
event_handlers.echo_reply_user_data = user_data;
|
|
268
|
+
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
bool
|
|
274
|
+
switch_set_vendor_handler( vendor_handler callback, void *user_data ) {
|
|
275
|
+
assert( callback != NULL );
|
|
276
|
+
assert( openflow_switch_interface_initialized );
|
|
277
|
+
|
|
278
|
+
debug( "Setting a vendor handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
279
|
+
|
|
280
|
+
event_handlers.vendor_callback = callback;
|
|
281
|
+
event_handlers.vendor_user_data = user_data;
|
|
282
|
+
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
bool
|
|
288
|
+
set_features_request_handler( features_request_handler callback, void *user_data ) {
|
|
289
|
+
assert( callback != NULL );
|
|
290
|
+
assert( openflow_switch_interface_initialized );
|
|
291
|
+
|
|
292
|
+
debug( "Setting a features request handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
293
|
+
|
|
294
|
+
event_handlers.features_request_callback = callback;
|
|
295
|
+
event_handlers.features_request_user_data = user_data;
|
|
296
|
+
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
bool
|
|
302
|
+
set_get_config_request_handler( get_config_request_handler callback, void *user_data ) {
|
|
303
|
+
assert( callback != NULL );
|
|
304
|
+
assert( openflow_switch_interface_initialized );
|
|
305
|
+
|
|
306
|
+
debug( "Setting a get config request handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
307
|
+
|
|
308
|
+
event_handlers.get_config_request_callback = callback;
|
|
309
|
+
event_handlers.get_config_request_user_data = user_data;
|
|
310
|
+
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
bool
|
|
316
|
+
set_set_config_handler( set_config_handler callback, void *user_data ) {
|
|
317
|
+
assert( callback != NULL );
|
|
318
|
+
assert( openflow_switch_interface_initialized );
|
|
319
|
+
|
|
320
|
+
debug( "Setting a set config handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
321
|
+
|
|
322
|
+
event_handlers.set_config_callback = callback;
|
|
323
|
+
event_handlers.set_config_user_data = user_data;
|
|
324
|
+
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
bool
|
|
330
|
+
set_packet_out_handler( packet_out_handler callback, void *user_data ) {
|
|
331
|
+
assert( callback != NULL );
|
|
332
|
+
assert( openflow_switch_interface_initialized );
|
|
333
|
+
|
|
334
|
+
debug( "Setting a packet out handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
335
|
+
|
|
336
|
+
event_handlers.packet_out_callback = callback;
|
|
337
|
+
event_handlers.packet_out_user_data = user_data;
|
|
338
|
+
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
bool
|
|
344
|
+
set_flow_mod_handler( flow_mod_handler callback, void *user_data ) {
|
|
345
|
+
assert( callback != NULL );
|
|
346
|
+
assert( openflow_switch_interface_initialized );
|
|
347
|
+
|
|
348
|
+
debug( "Setting a flow mod handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
349
|
+
|
|
350
|
+
event_handlers.flow_mod_callback = callback;
|
|
351
|
+
event_handlers.flow_mod_user_data = user_data;
|
|
352
|
+
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
bool
|
|
358
|
+
set_port_mod_handler( port_mod_handler callback, void *user_data ) {
|
|
359
|
+
assert( callback != NULL );
|
|
360
|
+
assert( openflow_switch_interface_initialized );
|
|
361
|
+
|
|
362
|
+
debug( "Setting a port mod handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
363
|
+
|
|
364
|
+
event_handlers.port_mod_callback = callback;
|
|
365
|
+
event_handlers.port_mod_user_data = user_data;
|
|
366
|
+
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
bool
|
|
372
|
+
set_stats_request_handler( stats_request_handler callback, void *user_data ) {
|
|
373
|
+
assert( callback != NULL );
|
|
374
|
+
assert( openflow_switch_interface_initialized );
|
|
375
|
+
|
|
376
|
+
debug( "Setting a stats request handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
377
|
+
|
|
378
|
+
event_handlers.stats_request_callback = callback;
|
|
379
|
+
event_handlers.stats_request_user_data = user_data;
|
|
380
|
+
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
bool
|
|
386
|
+
set_barrier_request_handler( barrier_request_handler callback, void *user_data ) {
|
|
387
|
+
assert( callback != NULL );
|
|
388
|
+
assert( openflow_switch_interface_initialized );
|
|
389
|
+
|
|
390
|
+
debug( "Setting a barrier request handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
391
|
+
|
|
392
|
+
event_handlers.barrier_request_callback = callback;
|
|
393
|
+
event_handlers.barrier_request_user_data = user_data;
|
|
394
|
+
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
bool
|
|
400
|
+
set_queue_get_config_request_handler( queue_get_config_request_handler callback, void *user_data ) {
|
|
401
|
+
assert( callback != NULL );
|
|
402
|
+
assert( openflow_switch_interface_initialized );
|
|
403
|
+
|
|
404
|
+
debug( "Setting a queue get config request handler ( callback = %p, user_data = %p ).", callback, user_data );
|
|
405
|
+
|
|
406
|
+
event_handlers.queue_get_config_request_callback = callback;
|
|
407
|
+
event_handlers.queue_get_config_request_user_data = user_data;
|
|
408
|
+
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
static bool
|
|
414
|
+
empty( const buffer *data ) {
|
|
415
|
+
if ( ( data == NULL ) || ( ( data != NULL ) && ( data->length == 0 ) ) ) {
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
static void
|
|
424
|
+
handle_hello( buffer *data ) {
|
|
425
|
+
assert( empty( data ) == false );
|
|
426
|
+
|
|
427
|
+
struct ofp_header *hello = data->data;
|
|
428
|
+
|
|
429
|
+
uint32_t transaction_id = ntohl( hello->xid );
|
|
430
|
+
uint8_t version = hello->version;
|
|
431
|
+
|
|
432
|
+
debug( "A hello message is received ( transaction_id = %#x, version = %#x ).", transaction_id, version );
|
|
433
|
+
|
|
434
|
+
if ( event_handlers.hello_callback == NULL ) {
|
|
435
|
+
debug( "Callback function for hello events is not set." );
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
debug( "Calling hello handler ( callback = %p, user_data = %p ).",
|
|
440
|
+
event_handlers.hello_callback, event_handlers.hello_user_data );
|
|
441
|
+
|
|
442
|
+
event_handlers.hello_callback( transaction_id,
|
|
443
|
+
version,
|
|
444
|
+
event_handlers.hello_user_data );
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
static void
|
|
449
|
+
handle_error( buffer *data ) {
|
|
450
|
+
assert( empty( data ) == false );
|
|
451
|
+
|
|
452
|
+
struct ofp_error_msg *error_msg = ( struct ofp_error_msg * ) data->data;
|
|
453
|
+
|
|
454
|
+
uint32_t transaction_id = ntohl( error_msg->header.xid );
|
|
455
|
+
uint16_t type = ntohs( error_msg->type );
|
|
456
|
+
uint16_t code = ntohs( error_msg->code );
|
|
457
|
+
|
|
458
|
+
buffer *body = duplicate_buffer( data );
|
|
459
|
+
remove_front_buffer( body, offsetof( struct ofp_error_msg, data ) );
|
|
460
|
+
|
|
461
|
+
debug( "An error message is received ( transaction_id = %#x, type = %u, code = %u, data length = %u ).",
|
|
462
|
+
transaction_id, type, code, body->length );
|
|
463
|
+
|
|
464
|
+
if ( event_handlers.error_callback == NULL ) {
|
|
465
|
+
debug( "Callback function for error events is not set." );
|
|
466
|
+
free_buffer( body );
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
debug( "Calling error handler ( callback = %p, user_data = %p ).",
|
|
471
|
+
event_handlers.error_callback, event_handlers.error_user_data );
|
|
472
|
+
|
|
473
|
+
event_handlers.error_callback( transaction_id,
|
|
474
|
+
type,
|
|
475
|
+
code,
|
|
476
|
+
body,
|
|
477
|
+
event_handlers.error_user_data );
|
|
478
|
+
|
|
479
|
+
free_buffer( body );
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
static void
|
|
484
|
+
handle_echo_request( buffer *data ) {
|
|
485
|
+
assert( empty( data ) == false );
|
|
486
|
+
|
|
487
|
+
struct ofp_header *header = data->data;
|
|
488
|
+
uint32_t transaction_id = htonl( header->xid );
|
|
489
|
+
uint16_t length = htons( header->length );
|
|
490
|
+
|
|
491
|
+
debug( "An echo request is received ( transaction_id = %#x, len = %u ).", transaction_id, length );
|
|
492
|
+
|
|
493
|
+
if ( event_handlers.echo_request_callback == NULL ) {
|
|
494
|
+
debug( "Callback function for echo request events is not set." );
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
buffer *body = NULL;
|
|
499
|
+
if ( ( length - sizeof( struct ofp_header ) ) > 0 ) {
|
|
500
|
+
body = duplicate_buffer( data );
|
|
501
|
+
remove_front_buffer( body, sizeof( struct ofp_header ) );
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
debug( "Calling echo request handler ( callback = %p, body = %p, user_data = %p ).",
|
|
505
|
+
event_handlers.echo_request_callback,
|
|
506
|
+
body,
|
|
507
|
+
event_handlers.echo_request_user_data );
|
|
508
|
+
|
|
509
|
+
event_handlers.echo_request_callback( transaction_id, body, event_handlers.set_config_user_data );
|
|
510
|
+
|
|
511
|
+
if ( body != NULL ) {
|
|
512
|
+
free_buffer( body );
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
static void
|
|
518
|
+
handle_echo_reply( buffer *data ) {
|
|
519
|
+
assert( empty( data ) == false );
|
|
520
|
+
|
|
521
|
+
struct ofp_header *header = data->data;
|
|
522
|
+
uint32_t transaction_id = htonl( header->xid );
|
|
523
|
+
uint16_t length = htons( header->length );
|
|
524
|
+
|
|
525
|
+
debug( "An echo reply is received ( transaction_id = %#x, len = %u ).", transaction_id, length );
|
|
526
|
+
|
|
527
|
+
if ( event_handlers.echo_reply_callback == NULL ) {
|
|
528
|
+
debug( "Callback function for echo reply events is not set." );
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
buffer *body = NULL;
|
|
533
|
+
if ( ( length - sizeof( struct ofp_header ) ) > 0 ) {
|
|
534
|
+
body = duplicate_buffer( data );
|
|
535
|
+
remove_front_buffer( body, sizeof( struct ofp_header ) );
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
debug( "Calling echo reply handler ( callback = %p, body = %p, user_data = %p ).",
|
|
539
|
+
event_handlers.echo_reply_callback,
|
|
540
|
+
body,
|
|
541
|
+
event_handlers.echo_reply_user_data );
|
|
542
|
+
|
|
543
|
+
event_handlers.echo_reply_callback( transaction_id, body, event_handlers.set_config_user_data );
|
|
544
|
+
|
|
545
|
+
if ( body != NULL ) {
|
|
546
|
+
free_buffer( body );
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
static void
|
|
552
|
+
handle_vendor( buffer *data ) {
|
|
553
|
+
assert( empty( data ) == false );
|
|
554
|
+
|
|
555
|
+
struct ofp_vendor_header *vendor_header = ( struct ofp_vendor_header * ) data->data;
|
|
556
|
+
|
|
557
|
+
uint32_t transaction_id = ntohl( vendor_header->header.xid );
|
|
558
|
+
uint32_t vendor = ntohl( vendor_header->vendor );
|
|
559
|
+
|
|
560
|
+
uint16_t body_length = ( uint16_t ) ( ntohs( vendor_header->header.length )
|
|
561
|
+
- sizeof( struct ofp_vendor_header ) );
|
|
562
|
+
|
|
563
|
+
debug( "A vendor message is received ( transaction_id = %#x, vendor = %#x, body length = %u ).",
|
|
564
|
+
transaction_id, vendor, body_length );
|
|
565
|
+
|
|
566
|
+
if ( event_handlers.vendor_callback == NULL ) {
|
|
567
|
+
debug( "Callback function for vendor events is not set." );
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
buffer *body = NULL;
|
|
572
|
+
if ( body_length > 0 ) {
|
|
573
|
+
body = duplicate_buffer( data );
|
|
574
|
+
remove_front_buffer( body, sizeof( struct ofp_vendor_header ) );
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
debug( "Calling vendor handler ( callback = %p, user_data = %p ).",
|
|
578
|
+
event_handlers.vendor_callback, event_handlers.vendor_user_data );
|
|
579
|
+
|
|
580
|
+
event_handlers.vendor_callback( transaction_id,
|
|
581
|
+
vendor,
|
|
582
|
+
body,
|
|
583
|
+
event_handlers.vendor_user_data );
|
|
584
|
+
|
|
585
|
+
if ( body != NULL ) {
|
|
586
|
+
free_buffer( body );
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
static void
|
|
592
|
+
handle_features_request( buffer *data ) {
|
|
593
|
+
assert( empty( data ) == false );
|
|
594
|
+
|
|
595
|
+
struct ofp_header *header = data->data;
|
|
596
|
+
|
|
597
|
+
uint32_t transaction_id = ntohl( header->xid );
|
|
598
|
+
|
|
599
|
+
debug( "A features request is received ( transaction_id = %#x ).", transaction_id );
|
|
600
|
+
|
|
601
|
+
if ( event_handlers.features_request_callback == NULL ) {
|
|
602
|
+
debug( "Callback function for features request events is not set." );
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
debug( "Calling features request handler ( callback = %p, user_data = %p ).",
|
|
607
|
+
event_handlers.features_request_callback,
|
|
608
|
+
event_handlers.features_request_user_data );
|
|
609
|
+
|
|
610
|
+
event_handlers.features_request_callback( transaction_id,
|
|
611
|
+
event_handlers.features_request_user_data );
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
|
|
615
|
+
static void
|
|
616
|
+
handle_get_config_request( buffer *data ) {
|
|
617
|
+
assert( empty( data ) == false );
|
|
618
|
+
|
|
619
|
+
struct ofp_header *header = data->data;
|
|
620
|
+
|
|
621
|
+
uint32_t transaction_id = ntohl( header->xid );
|
|
622
|
+
|
|
623
|
+
debug( "A get config request is received ( transaction_id = %#x ).", transaction_id );
|
|
624
|
+
|
|
625
|
+
if ( event_handlers.get_config_request_callback == NULL ) {
|
|
626
|
+
debug( "Callback function for get config request events is not set." );
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
debug( "Calling get config request handler ( callback = %p, user_data = %p ).",
|
|
631
|
+
event_handlers.get_config_request_callback,
|
|
632
|
+
event_handlers.get_config_request_user_data );
|
|
633
|
+
|
|
634
|
+
event_handlers.get_config_request_callback( transaction_id,
|
|
635
|
+
event_handlers.get_config_request_user_data );
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
static void
|
|
640
|
+
handle_set_config( buffer *data ) {
|
|
641
|
+
assert( empty( data ) == false );
|
|
642
|
+
|
|
643
|
+
struct ofp_switch_config *config = data->data;
|
|
644
|
+
|
|
645
|
+
uint32_t transaction_id = ntohl( config->header.xid );
|
|
646
|
+
uint16_t flags = ntohs( config->flags );
|
|
647
|
+
uint16_t miss_send_len = ntohs( config->miss_send_len );
|
|
648
|
+
|
|
649
|
+
debug( "A set config is received ( transaction_id = %#x, flags = %#x, miss_send_len = %u ).",
|
|
650
|
+
transaction_id, flags, miss_send_len );
|
|
651
|
+
|
|
652
|
+
if ( event_handlers.set_config_callback == NULL ) {
|
|
653
|
+
debug( "Callback function for set config events is not set." );
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
debug( "Calling set config handler ( callback = %p, user_data = %p ).",
|
|
658
|
+
event_handlers.set_config_callback,
|
|
659
|
+
event_handlers.set_config_user_data );
|
|
660
|
+
|
|
661
|
+
event_handlers.set_config_callback( transaction_id, flags, miss_send_len,
|
|
662
|
+
event_handlers.set_config_user_data );
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
static void
|
|
667
|
+
handle_packet_out( buffer *data ) {
|
|
668
|
+
assert( empty( data ) == false );
|
|
669
|
+
|
|
670
|
+
struct ofp_packet_out *packet_out = data->data;
|
|
671
|
+
|
|
672
|
+
uint32_t transaction_id = ntohl( packet_out->header.xid );
|
|
673
|
+
uint32_t buffer_id = ntohl( packet_out->buffer_id );
|
|
674
|
+
uint16_t in_port = ntohs( packet_out->in_port );
|
|
675
|
+
size_t actions_len = ntohs( packet_out->actions_len );
|
|
676
|
+
openflow_actions *actions = NULL;
|
|
677
|
+
if ( actions_len > 0 ) {
|
|
678
|
+
actions = create_actions();
|
|
679
|
+
void *actions_p = packet_out->actions;
|
|
680
|
+
while ( actions_len > 0 ) {
|
|
681
|
+
struct ofp_action_header *ah = actions_p;
|
|
682
|
+
ntoh_action( ah, ah );
|
|
683
|
+
actions_len -= ah->len;
|
|
684
|
+
actions_p = ( char * ) actions_p + ah->len;
|
|
685
|
+
|
|
686
|
+
void *action = xmalloc( ah->len );
|
|
687
|
+
memcpy( action, ah, ah->len );
|
|
688
|
+
append_to_tail( &actions->list, ( void * ) action );
|
|
689
|
+
actions->n_actions++;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
buffer *frame = NULL;
|
|
694
|
+
actions_len = ntohs( packet_out->actions_len );
|
|
695
|
+
size_t frame_length = ntohs( packet_out->header.length ) - offsetof( struct ofp_packet_out, actions ) - actions_len;
|
|
696
|
+
if ( frame_length > 0 ) {
|
|
697
|
+
frame = alloc_buffer_with_length( frame_length );
|
|
698
|
+
void *p = append_back_buffer( frame, frame_length );
|
|
699
|
+
size_t offset = offsetof( struct ofp_packet_out, actions ) + actions_len;
|
|
700
|
+
memcpy( p, ( char * ) packet_out + offset, frame_length );
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
debug( "A packet-out is received ( transaction_id = %#x, buffer_id = %#x, in_port = %u, "
|
|
704
|
+
"actions_len = %u, frame_length = %u ).",
|
|
705
|
+
transaction_id, buffer_id, in_port, actions_len, frame_length );
|
|
706
|
+
|
|
707
|
+
if ( event_handlers.packet_out_callback == NULL ) {
|
|
708
|
+
debug( "Callback function for packet-out events is not set." );
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
debug( "Calling packet-outhandler ( callback = %p, user_data = %p ).",
|
|
713
|
+
event_handlers.packet_out_callback,
|
|
714
|
+
event_handlers.packet_out_user_data );
|
|
715
|
+
|
|
716
|
+
event_handlers.packet_out_callback( transaction_id, buffer_id, in_port, actions, frame,
|
|
717
|
+
event_handlers.packet_out_user_data );
|
|
718
|
+
|
|
719
|
+
if ( actions != NULL ) {
|
|
720
|
+
delete_actions( actions );
|
|
721
|
+
}
|
|
722
|
+
if ( frame != NULL ) {
|
|
723
|
+
free_buffer( frame );
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
static void
|
|
729
|
+
handle_flow_mod( buffer *data ) {
|
|
730
|
+
assert( empty( data ) == false );
|
|
731
|
+
|
|
732
|
+
struct ofp_flow_mod *flow_mod = data->data;
|
|
733
|
+
|
|
734
|
+
uint32_t transaction_id = ntohl( flow_mod->header.xid );
|
|
735
|
+
struct ofp_match match;
|
|
736
|
+
ntoh_match( &match, &flow_mod->match );
|
|
737
|
+
uint64_t cookie = ntohll( flow_mod->cookie );
|
|
738
|
+
uint16_t command = ntohs( flow_mod->command );
|
|
739
|
+
uint16_t idle_timeout = ntohs( flow_mod->idle_timeout );
|
|
740
|
+
uint16_t hard_timeout = ntohs( flow_mod->hard_timeout );
|
|
741
|
+
uint16_t priority = ntohs( flow_mod->priority );
|
|
742
|
+
uint32_t buffer_id = ntohl( flow_mod->buffer_id );
|
|
743
|
+
uint16_t out_port = ntohs( flow_mod->out_port );
|
|
744
|
+
uint16_t flags = ntohs( flow_mod->flags );
|
|
745
|
+
|
|
746
|
+
size_t actions_length = ntohs( flow_mod->header.length ) - offsetof( struct ofp_flow_mod, actions );
|
|
747
|
+
openflow_actions *actions = NULL;
|
|
748
|
+
if ( actions_length > 0 ) {
|
|
749
|
+
actions = create_actions();
|
|
750
|
+
void *actions_p = flow_mod->actions;
|
|
751
|
+
while ( actions_length > 0 ) {
|
|
752
|
+
struct ofp_action_header *ah = actions_p;
|
|
753
|
+
ntoh_action( ah, ah );
|
|
754
|
+
actions_length -= ah->len;
|
|
755
|
+
actions_p = ( char * ) actions_p + ah->len;
|
|
756
|
+
|
|
757
|
+
void *action = xmalloc( ah->len );
|
|
758
|
+
memcpy( action, ah, ah->len );
|
|
759
|
+
append_to_tail( &actions->list, ( void * ) action );
|
|
760
|
+
actions->n_actions++;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if ( get_logging_level() >= LOG_DEBUG ) {
|
|
765
|
+
char match_str[ 256 ];
|
|
766
|
+
match_to_string( &match, match_str, sizeof( match_str ) );
|
|
767
|
+
debug( "A flow modification is received ( transaction_id = %#x, match = [%s], cookie = %#" PRIx64 ", "
|
|
768
|
+
"command = %#x, idle_timeout = %u, hard_timeout = %u, priority = %u, buffer_id = %#x, "
|
|
769
|
+
"out_port = %u, flags = %#x ).",
|
|
770
|
+
transaction_id, match_str, cookie, command, idle_timeout, hard_timeout, priority, buffer_id,
|
|
771
|
+
out_port, flags );
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
if ( event_handlers.flow_mod_callback == NULL ) {
|
|
775
|
+
debug( "Callback function for flow modification events is not set." );
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
debug( "Calling flow modification handler ( callback = %p, user_data = %p ).",
|
|
780
|
+
event_handlers.flow_mod_callback,
|
|
781
|
+
event_handlers.flow_mod_user_data );
|
|
782
|
+
|
|
783
|
+
event_handlers.flow_mod_callback( transaction_id, match, cookie, command, idle_timeout, hard_timeout,
|
|
784
|
+
priority, buffer_id, out_port, flags, actions,
|
|
785
|
+
event_handlers.flow_mod_user_data );
|
|
786
|
+
|
|
787
|
+
if ( actions != NULL ) {
|
|
788
|
+
delete_actions( actions );
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
static void
|
|
794
|
+
handle_port_mod( buffer *data ) {
|
|
795
|
+
assert( empty( data ) == false );
|
|
796
|
+
|
|
797
|
+
struct ofp_port_mod *port_mod = data->data;
|
|
798
|
+
|
|
799
|
+
uint32_t transaction_id = ntohl( port_mod->header.xid );
|
|
800
|
+
uint16_t port_no = ntohs( port_mod->port_no );
|
|
801
|
+
uint8_t hw_addr[ OFP_ETH_ALEN ];
|
|
802
|
+
memcpy( hw_addr, port_mod->hw_addr, OFP_ETH_ALEN );
|
|
803
|
+
uint32_t config = ntohl( port_mod->config );
|
|
804
|
+
uint32_t mask = ntohl( port_mod->mask );
|
|
805
|
+
uint32_t advertise = ntohl( port_mod->advertise );
|
|
806
|
+
|
|
807
|
+
debug( "A port modification is received ( transaction_id = %#x, port_no = %u, "
|
|
808
|
+
"hw_addr = %02x:%02x:%02x:%02x:%02x:%02x, config = %#x, mask = %#x, advertise = %#x ).",
|
|
809
|
+
transaction_id, port_no,
|
|
810
|
+
hw_addr[ 0 ], hw_addr[ 1 ], hw_addr[ 2 ], hw_addr[ 3 ], hw_addr[ 4 ], hw_addr[ 5 ],
|
|
811
|
+
config, mask, advertise );
|
|
812
|
+
|
|
813
|
+
if ( event_handlers.port_mod_callback == NULL ) {
|
|
814
|
+
debug( "Callback function for port modification events is not set." );
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
debug( "Calling port modification handler ( callback = %p, user_data = %p ).",
|
|
819
|
+
event_handlers.port_mod_callback,
|
|
820
|
+
event_handlers.port_mod_user_data );
|
|
821
|
+
|
|
822
|
+
event_handlers.port_mod_callback( transaction_id, port_no, hw_addr, config, mask, advertise,
|
|
823
|
+
event_handlers.barrier_request_user_data );
|
|
824
|
+
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
static void
|
|
829
|
+
handle_stats_request( buffer *data ) {
|
|
830
|
+
assert( empty( data ) == false );
|
|
831
|
+
|
|
832
|
+
struct ofp_stats_request *stats_request = data->data;
|
|
833
|
+
|
|
834
|
+
uint32_t transaction_id = ntohl( stats_request->header.xid );
|
|
835
|
+
uint16_t type = ntohs( stats_request->type );
|
|
836
|
+
uint16_t flags = ntohs( stats_request->flags );
|
|
837
|
+
|
|
838
|
+
size_t body_length = ntohs( stats_request->header.length ) - offsetof( struct ofp_stats_request, body );
|
|
839
|
+
buffer *body = NULL;
|
|
840
|
+
if ( body_length > 0 ) {
|
|
841
|
+
body = alloc_buffer_with_length( body_length );
|
|
842
|
+
void *p = append_back_buffer( body, body_length );
|
|
843
|
+
memcpy( p, stats_request->body, body_length );
|
|
844
|
+
|
|
845
|
+
switch ( type ) {
|
|
846
|
+
case OFPST_FLOW:
|
|
847
|
+
{
|
|
848
|
+
struct ofp_flow_stats_request *flow = p;
|
|
849
|
+
ntoh_match( &flow->match, &flow->match );
|
|
850
|
+
flow->out_port = ntohs( flow->out_port );
|
|
851
|
+
}
|
|
852
|
+
break;
|
|
853
|
+
|
|
854
|
+
case OFPST_AGGREGATE:
|
|
855
|
+
{
|
|
856
|
+
struct ofp_aggregate_stats_request *aggregate = p;
|
|
857
|
+
ntoh_match( &aggregate->match, &aggregate->match );
|
|
858
|
+
aggregate->out_port = ntohs( aggregate->out_port );
|
|
859
|
+
}
|
|
860
|
+
break;
|
|
861
|
+
|
|
862
|
+
case OFPST_PORT:
|
|
863
|
+
{
|
|
864
|
+
struct ofp_port_stats_request *port = p;
|
|
865
|
+
port->port_no = ntohs( port->port_no );
|
|
866
|
+
}
|
|
867
|
+
break;
|
|
868
|
+
|
|
869
|
+
case OFPST_VENDOR:
|
|
870
|
+
{
|
|
871
|
+
uint32_t *vendor_id = p;
|
|
872
|
+
*vendor_id = ntohl( *vendor_id );
|
|
873
|
+
}
|
|
874
|
+
break;
|
|
875
|
+
|
|
876
|
+
default:
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
debug( "A stats request is received ( transaction_id = %#x, type = %#x, flags = %#x ).",
|
|
882
|
+
transaction_id, type, flags );
|
|
883
|
+
|
|
884
|
+
if ( event_handlers.stats_request_callback == NULL ) {
|
|
885
|
+
debug( "Callback function for stats request events is not set." );
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
debug( "Calling stats request handler ( callback = %p, user_data = %p ).",
|
|
890
|
+
event_handlers.stats_request_callback,
|
|
891
|
+
event_handlers.stats_request_user_data );
|
|
892
|
+
|
|
893
|
+
event_handlers.stats_request_callback( transaction_id, type, flags, body,
|
|
894
|
+
event_handlers.stats_request_user_data );
|
|
895
|
+
|
|
896
|
+
if ( body_length > 0 && body != NULL ) {
|
|
897
|
+
free_buffer( body );
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
static void
|
|
903
|
+
handle_barrier_request( buffer *data ) {
|
|
904
|
+
assert( empty( data ) == false );
|
|
905
|
+
|
|
906
|
+
struct ofp_header *header = data->data;
|
|
907
|
+
|
|
908
|
+
uint32_t transaction_id = ntohl( header->xid );
|
|
909
|
+
|
|
910
|
+
debug( "A barrier request is received ( transaction_id = %#x ).", transaction_id );
|
|
911
|
+
|
|
912
|
+
if ( event_handlers.barrier_request_callback == NULL ) {
|
|
913
|
+
debug( "Callback function for barrier request events is not set." );
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
debug( "Calling barrier request handler ( callback = %p, user_data = %p ).",
|
|
918
|
+
event_handlers.barrier_request_callback,
|
|
919
|
+
event_handlers.barrier_request_user_data );
|
|
920
|
+
|
|
921
|
+
event_handlers.barrier_request_callback( transaction_id,
|
|
922
|
+
event_handlers.barrier_request_user_data );
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
static void
|
|
927
|
+
handle_queue_get_config_request( buffer *data ) {
|
|
928
|
+
assert( empty( data ) == false );
|
|
929
|
+
|
|
930
|
+
struct ofp_queue_get_config_request *queue_get_config_request = data->data;
|
|
931
|
+
|
|
932
|
+
uint32_t transaction_id = ntohl( queue_get_config_request->header.xid );
|
|
933
|
+
uint16_t port = ntohs( queue_get_config_request->port );
|
|
934
|
+
|
|
935
|
+
debug( "A queue get config request is received ( transaction_id = %#x, port = %u ).",
|
|
936
|
+
transaction_id, port );
|
|
937
|
+
|
|
938
|
+
if ( event_handlers.queue_get_config_request_callback == NULL ) {
|
|
939
|
+
debug( "Callback function for queue get config request events is not set." );
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
debug( "Calling queue get config request handler ( callback = %p, user_data = %p ).",
|
|
944
|
+
event_handlers.queue_get_config_request_callback,
|
|
945
|
+
event_handlers.queue_get_config_request_user_data );
|
|
946
|
+
|
|
947
|
+
event_handlers.queue_get_config_request_callback( transaction_id, port,
|
|
948
|
+
event_handlers.queue_get_config_request_user_data );
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
static void
|
|
953
|
+
handle_controller_connected() {
|
|
954
|
+
if ( event_handlers.controller_connected_callback == NULL ) {
|
|
955
|
+
debug( "Callback function for controller connected events is not set." );
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
event_handlers.controller_connected_callback( event_handlers.controller_connected_user_data );
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
static void
|
|
964
|
+
handle_controller_disconnected() {
|
|
965
|
+
if ( event_handlers.controller_disconnected_callback == NULL ) {
|
|
966
|
+
debug( "Callback function for controller disconnected events is not set." );
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
event_handlers.controller_disconnected_callback( event_handlers.controller_disconnected_user_data );
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
static bool
|
|
975
|
+
handle_openflow_message( buffer *message ) {
|
|
976
|
+
debug( "An OpenFlow message is received from remote." );
|
|
977
|
+
|
|
978
|
+
assert( message != NULL );
|
|
979
|
+
assert( message->length >= sizeof( struct ofp_header ) );
|
|
980
|
+
|
|
981
|
+
int ret = validate_openflow_message( message );
|
|
982
|
+
if ( ret < 0 ) {
|
|
983
|
+
error( "Failed to validate an OpenFlow message ( code = %d, length = %u ).", ret, message->length );
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
ret = true;
|
|
988
|
+
struct ofp_header *header = ( struct ofp_header * ) message->data;
|
|
989
|
+
|
|
990
|
+
switch ( header->type ) {
|
|
991
|
+
case OFPT_HELLO:
|
|
992
|
+
handle_hello( message );
|
|
993
|
+
break;
|
|
994
|
+
case OFPT_ERROR:
|
|
995
|
+
handle_error( message );
|
|
996
|
+
break;
|
|
997
|
+
case OFPT_ECHO_REQUEST:
|
|
998
|
+
handle_echo_request( message );
|
|
999
|
+
break;
|
|
1000
|
+
case OFPT_ECHO_REPLY:
|
|
1001
|
+
handle_echo_reply( message );
|
|
1002
|
+
break;
|
|
1003
|
+
case OFPT_VENDOR:
|
|
1004
|
+
handle_vendor( message);
|
|
1005
|
+
break;
|
|
1006
|
+
case OFPT_FEATURES_REQUEST:
|
|
1007
|
+
handle_features_request( message );
|
|
1008
|
+
break;
|
|
1009
|
+
case OFPT_GET_CONFIG_REQUEST:
|
|
1010
|
+
handle_get_config_request( message );
|
|
1011
|
+
break;
|
|
1012
|
+
case OFPT_SET_CONFIG:
|
|
1013
|
+
handle_set_config( message );
|
|
1014
|
+
break;
|
|
1015
|
+
case OFPT_PACKET_OUT:
|
|
1016
|
+
handle_packet_out( message );
|
|
1017
|
+
break;
|
|
1018
|
+
case OFPT_FLOW_MOD:
|
|
1019
|
+
handle_flow_mod( message );
|
|
1020
|
+
break;
|
|
1021
|
+
case OFPT_PORT_MOD:
|
|
1022
|
+
handle_port_mod( message );
|
|
1023
|
+
break;
|
|
1024
|
+
case OFPT_STATS_REQUEST:
|
|
1025
|
+
handle_stats_request( message );
|
|
1026
|
+
break;
|
|
1027
|
+
case OFPT_BARRIER_REQUEST:
|
|
1028
|
+
handle_barrier_request( message );
|
|
1029
|
+
break;
|
|
1030
|
+
case OFPT_QUEUE_GET_CONFIG_REQUEST:
|
|
1031
|
+
handle_queue_get_config_request( message );
|
|
1032
|
+
break;
|
|
1033
|
+
default:
|
|
1034
|
+
error( "Unhandled OpenFlow message ( type = %u ).", header->type );
|
|
1035
|
+
ret = false;
|
|
1036
|
+
break;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
return ret;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
static bool
|
|
1044
|
+
send_openflow_message_to_secure_channel( buffer *message, void *user_data ) {
|
|
1045
|
+
assert( user_data == NULL );
|
|
1046
|
+
|
|
1047
|
+
return send_message_to_secure_channel( message );
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
static bool
|
|
1052
|
+
send_openflow_message_to_local( buffer *message, void *user_data ) {
|
|
1053
|
+
char *service_name = user_data;
|
|
1054
|
+
size_t service_name_length = strlen( service_name ) + 1;
|
|
1055
|
+
size_t service_header_length = sizeof( openflow_service_header_t ) + service_name_length;
|
|
1056
|
+
openflow_service_header_t *service_header = append_front_buffer( message, service_header_length );
|
|
1057
|
+
service_header->service_name_length = htons( ( uint16_t ) service_name_length );
|
|
1058
|
+
memcpy( ( char * ) service_header + sizeof( openflow_service_header_t ), service_name, service_name_length );
|
|
1059
|
+
|
|
1060
|
+
return send_message( service_name, MESSENGER_OPENFLOW_MESSAGE, message->data, message->length );
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
bool
|
|
1065
|
+
switch_send_openflow_message( buffer *message ) {
|
|
1066
|
+
assert( message != NULL );
|
|
1067
|
+
assert( message->length >= sizeof( struct ofp_header ) );
|
|
1068
|
+
|
|
1069
|
+
struct ofp_header *header = message->data;
|
|
1070
|
+
uint32_t transaction_id = ntohl( header->xid );
|
|
1071
|
+
openflow_context *context = lookup_context( transaction_id );
|
|
1072
|
+
if ( context != NULL ) {
|
|
1073
|
+
assert( context->send_callback != NULL );
|
|
1074
|
+
return context->send_callback( message, context->user_data );
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
return send_openflow_message_to_secure_channel( message, NULL );
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
bool
|
|
1082
|
+
handle_secure_channel_message( buffer *message ) {
|
|
1083
|
+
debug( "An OpenFlow message is received from remove." );
|
|
1084
|
+
|
|
1085
|
+
assert( message != NULL );
|
|
1086
|
+
assert( message->length >= sizeof( struct ofp_header ) );
|
|
1087
|
+
|
|
1088
|
+
struct ofp_header *header = message->data;
|
|
1089
|
+
|
|
1090
|
+
save_context( ntohl( header->xid ), message, send_openflow_message_to_secure_channel, NULL );
|
|
1091
|
+
|
|
1092
|
+
return handle_openflow_message( message );
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
static void
|
|
1097
|
+
handle_local_message( uint16_t tag, void *data, size_t length ) {
|
|
1098
|
+
assert( data != NULL );
|
|
1099
|
+
assert( length >= sizeof( openflow_service_header_t ) );
|
|
1100
|
+
|
|
1101
|
+
debug( "A message is received from remote ( tag = %u, data = %p, length = %u ).", tag, data, length );
|
|
1102
|
+
|
|
1103
|
+
switch ( tag ) {
|
|
1104
|
+
case MESSENGER_OPENFLOW_MESSAGE:
|
|
1105
|
+
{
|
|
1106
|
+
openflow_service_header_t *header = data;
|
|
1107
|
+
uint16_t service_name_length = ntohs( header->service_name_length );
|
|
1108
|
+
size_t ofp_offset = sizeof( openflow_service_header_t ) + service_name_length;
|
|
1109
|
+
size_t ofp_length = length - ofp_offset;
|
|
1110
|
+
buffer *message = alloc_buffer_with_length( ofp_length );
|
|
1111
|
+
char *p = append_back_buffer( message, ofp_length );
|
|
1112
|
+
memcpy( p, ( char * ) data + ofp_offset, ofp_length );
|
|
1113
|
+
char *service_name = strndup( ( char * ) data + sizeof( openflow_service_header_t ), service_name_length );
|
|
1114
|
+
|
|
1115
|
+
save_context( ntohl( ( ( struct ofp_header * ) p )->xid ), message, send_openflow_message_to_local,
|
|
1116
|
+
service_name );
|
|
1117
|
+
|
|
1118
|
+
handle_openflow_message( message );
|
|
1119
|
+
}
|
|
1120
|
+
break;
|
|
1121
|
+
default:
|
|
1122
|
+
break;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
bool
|
|
1128
|
+
init_openflow_switch_interface( const uint64_t datapath_id, uint32_t controller_ip, uint16_t controller_port ) {
|
|
1129
|
+
debug( "Initializing OpenFlow Switch Interface ( datapath_id = %#" PRIx64 ", controller_ip = %#x, controller_port = %u ).",
|
|
1130
|
+
datapath_id, controller_ip, controller_port );
|
|
1131
|
+
|
|
1132
|
+
if ( openflow_switch_interface_is_initialized() ) {
|
|
1133
|
+
error( "OpenFlow Switch Interface is already initialized." );
|
|
1134
|
+
return false;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
bool ret = init_secure_channel( controller_ip, controller_port,
|
|
1138
|
+
handle_controller_connected, handle_controller_disconnected );
|
|
1139
|
+
if ( ret == false ) {
|
|
1140
|
+
error( "Failed to initialize a secure chanel." );
|
|
1141
|
+
return false;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
memset( &event_handlers, 0, sizeof( openflow_event_handlers ) );
|
|
1146
|
+
memset( &config, 0, sizeof( openflow_switch_config ) );
|
|
1147
|
+
|
|
1148
|
+
config.datapath_id = datapath_id;
|
|
1149
|
+
config.controller.ip = controller_ip;
|
|
1150
|
+
config.controller.port = controller_port;
|
|
1151
|
+
|
|
1152
|
+
init_context();
|
|
1153
|
+
|
|
1154
|
+
add_periodic_event_callback( 5, age_contexts, NULL );
|
|
1155
|
+
add_message_received_callback( get_chibach_name(), handle_local_message );
|
|
1156
|
+
|
|
1157
|
+
openflow_switch_interface_initialized = true;
|
|
1158
|
+
|
|
1159
|
+
return true;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
bool
|
|
1164
|
+
finalize_openflow_switch_interface() {
|
|
1165
|
+
if ( !openflow_switch_interface_is_initialized() ) {
|
|
1166
|
+
error( "OpenFlow Switch Interface is not initialized." );
|
|
1167
|
+
return false;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
finalize_secure_channel();
|
|
1171
|
+
|
|
1172
|
+
delete_timer_event( age_contexts, NULL );
|
|
1173
|
+
finalize_context();
|
|
1174
|
+
|
|
1175
|
+
openflow_switch_interface_initialized = false;
|
|
1176
|
+
|
|
1177
|
+
return true;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
static const buffer *
|
|
1182
|
+
get_openflow_message( uint32_t transaction_id ) {
|
|
1183
|
+
openflow_context *context = lookup_context( transaction_id );
|
|
1184
|
+
if ( context == NULL ) {
|
|
1185
|
+
return NULL;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
return context->message;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
bool
|
|
1193
|
+
send_error_message( uint32_t transaction_id, uint16_t type, uint16_t code ) {
|
|
1194
|
+
buffer *data = NULL;
|
|
1195
|
+
switch ( type ) {
|
|
1196
|
+
case OFPET_HELLO_FAILED:
|
|
1197
|
+
{
|
|
1198
|
+
switch ( code ) {
|
|
1199
|
+
case OFPHFC_INCOMPATIBLE:
|
|
1200
|
+
{
|
|
1201
|
+
const char *description = "Incompatible OpenFlow version.";
|
|
1202
|
+
size_t length = strlen( description ) + 1;
|
|
1203
|
+
data = alloc_buffer_with_length ( length );
|
|
1204
|
+
void *p = append_back_buffer( data, length );
|
|
1205
|
+
strncpy( p, description, length );
|
|
1206
|
+
}
|
|
1207
|
+
break;
|
|
1208
|
+
case OFPHFC_EPERM:
|
|
1209
|
+
{
|
|
1210
|
+
const char *description = "Permissions error.";
|
|
1211
|
+
size_t length = strlen( description ) + 1;
|
|
1212
|
+
data = alloc_buffer_with_length ( length );
|
|
1213
|
+
void *p = append_back_buffer( data, length );
|
|
1214
|
+
strncpy( p, description, length );
|
|
1215
|
+
}
|
|
1216
|
+
break;
|
|
1217
|
+
default:
|
|
1218
|
+
error( "Undefined error code ( type = %#x, code = %#x ).", type, code );
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
break;
|
|
1223
|
+
|
|
1224
|
+
case OFPET_BAD_REQUEST:
|
|
1225
|
+
{
|
|
1226
|
+
switch ( code ) {
|
|
1227
|
+
case OFPBRC_BAD_VERSION:
|
|
1228
|
+
case OFPBRC_BAD_TYPE:
|
|
1229
|
+
case OFPBRC_BAD_STAT:
|
|
1230
|
+
case OFPBRC_BAD_VENDOR:
|
|
1231
|
+
case OFPBRC_BAD_SUBTYPE:
|
|
1232
|
+
case OFPBRC_EPERM:
|
|
1233
|
+
case OFPBRC_BAD_LEN:
|
|
1234
|
+
case OFPBRC_BUFFER_EMPTY:
|
|
1235
|
+
case OFPBRC_BUFFER_UNKNOWN:
|
|
1236
|
+
{
|
|
1237
|
+
const buffer *original_message = get_openflow_message( transaction_id );
|
|
1238
|
+
if ( original_message != NULL ) {
|
|
1239
|
+
data = duplicate_buffer( original_message );
|
|
1240
|
+
if ( data->length > 64 ) {
|
|
1241
|
+
data->length = 64;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
break;
|
|
1246
|
+
default:
|
|
1247
|
+
error( "Undefined error code ( type = %#x, code = %#x ).", type, code );
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
break;
|
|
1252
|
+
|
|
1253
|
+
case OFPET_BAD_ACTION:
|
|
1254
|
+
{
|
|
1255
|
+
switch ( code ) {
|
|
1256
|
+
case OFPBAC_BAD_TYPE:
|
|
1257
|
+
case OFPBAC_BAD_LEN:
|
|
1258
|
+
case OFPBAC_BAD_VENDOR:
|
|
1259
|
+
case OFPBAC_BAD_VENDOR_TYPE:
|
|
1260
|
+
case OFPBAC_BAD_OUT_PORT:
|
|
1261
|
+
case OFPBAC_BAD_ARGUMENT:
|
|
1262
|
+
case OFPBAC_EPERM:
|
|
1263
|
+
case OFPBAC_TOO_MANY:
|
|
1264
|
+
case OFPBAC_BAD_QUEUE:
|
|
1265
|
+
{
|
|
1266
|
+
const buffer *original_message = get_openflow_message( transaction_id );
|
|
1267
|
+
if ( original_message != NULL ) {
|
|
1268
|
+
data = duplicate_buffer( original_message );
|
|
1269
|
+
if ( data->length > 64 ) {
|
|
1270
|
+
data->length = 64;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
break;
|
|
1275
|
+
default:
|
|
1276
|
+
error( "Undefined error code ( type = %#x, code = %#x ).", type, code );
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
}
|
|
1281
|
+
break;
|
|
1282
|
+
|
|
1283
|
+
case OFPET_FLOW_MOD_FAILED:
|
|
1284
|
+
{
|
|
1285
|
+
switch ( code ) {
|
|
1286
|
+
case OFPFMFC_ALL_TABLES_FULL:
|
|
1287
|
+
case OFPFMFC_OVERLAP:
|
|
1288
|
+
case OFPFMFC_EPERM:
|
|
1289
|
+
case OFPFMFC_BAD_EMERG_TIMEOUT:
|
|
1290
|
+
case OFPFMFC_BAD_COMMAND:
|
|
1291
|
+
case OFPFMFC_UNSUPPORTED:
|
|
1292
|
+
{
|
|
1293
|
+
const buffer *original_message = get_openflow_message( transaction_id );
|
|
1294
|
+
if ( original_message != NULL ) {
|
|
1295
|
+
data = duplicate_buffer( original_message );
|
|
1296
|
+
if ( data->length > 64 ) {
|
|
1297
|
+
data->length = 64;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
break;
|
|
1302
|
+
default:
|
|
1303
|
+
error( "Undefined error code ( type = %#x, code = %#x ).", type, code );
|
|
1304
|
+
return false;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
break;
|
|
1308
|
+
|
|
1309
|
+
case OFPET_PORT_MOD_FAILED:
|
|
1310
|
+
{
|
|
1311
|
+
switch ( code ) {
|
|
1312
|
+
case OFPPMFC_BAD_PORT:
|
|
1313
|
+
case OFPPMFC_BAD_HW_ADDR:
|
|
1314
|
+
{
|
|
1315
|
+
const buffer *original_message = get_openflow_message( transaction_id );
|
|
1316
|
+
if ( original_message != NULL ) {
|
|
1317
|
+
data = duplicate_buffer( original_message );
|
|
1318
|
+
if ( data->length > 64 ) {
|
|
1319
|
+
data->length = 64;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
break;
|
|
1324
|
+
default:
|
|
1325
|
+
error( "Undefined error code ( type = %#x, code = %#x ).", type, code );
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
break;
|
|
1330
|
+
|
|
1331
|
+
case OFPET_QUEUE_OP_FAILED:
|
|
1332
|
+
{
|
|
1333
|
+
switch ( code ) {
|
|
1334
|
+
case OFPQOFC_BAD_PORT:
|
|
1335
|
+
case OFPQOFC_BAD_QUEUE:
|
|
1336
|
+
case OFPQOFC_EPERM:
|
|
1337
|
+
{
|
|
1338
|
+
const buffer *original_message = get_openflow_message( transaction_id );
|
|
1339
|
+
if ( original_message != NULL ) {
|
|
1340
|
+
data = duplicate_buffer( original_message );
|
|
1341
|
+
if ( data->length > 64 ) {
|
|
1342
|
+
data->length = 64;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
break;
|
|
1347
|
+
default:
|
|
1348
|
+
error( "Undefined error code ( type = %#x, code = %#x ).", type, code );
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
break;
|
|
1353
|
+
|
|
1354
|
+
default:
|
|
1355
|
+
error( "Undefined error type ( type = %#x, code = %#x ).", type, code );
|
|
1356
|
+
return false;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
buffer *err = create_error( transaction_id, type, code, data );
|
|
1360
|
+
bool ret = switch_send_openflow_message( err );
|
|
1361
|
+
if ( !ret ) {
|
|
1362
|
+
error( "Failed to send an error message ( transaction_id = %#x, type = %#x, code = %#x ).",
|
|
1363
|
+
transaction_id, type, code );
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
free_buffer( err );
|
|
1367
|
+
if ( data != NULL ) {
|
|
1368
|
+
free_buffer( data );
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
return ret;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
|
|
1375
|
+
/*
|
|
1376
|
+
* Local variables:
|
|
1377
|
+
* c-basic-offset: 2
|
|
1378
|
+
* indent-tabs-mode: nil
|
|
1379
|
+
* End:
|
|
1380
|
+
*/
|