trema 0.3.16 → 0.3.17
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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rvmrc +52 -0
- data/.travis.yml +3 -0
- data/Gemfile +1 -1
- data/Rakefile +259 -1
- data/Rantfile +79 -216
- data/features/.nav +12 -0
- data/features/dsl/switch_port_specifier.feature +15 -0
- data/features/examples/switch-event/C-add_forward_entry.feature +130 -0
- data/features/examples/switch-event/C-delete_forward_entry.feature +97 -0
- data/features/examples/switch-event/C-dump_forward_entries.feature +80 -0
- data/features/examples/switch-event/C-set_forward_entries.feature +85 -0
- data/features/examples/switch-event/README.md +40 -0
- data/features/examples/switch-event/add_forward_entry.feature +142 -0
- data/features/examples/switch-event/delete_forward_entry.feature +142 -0
- data/features/examples/switch-event/dump_forward_entries.feature +91 -0
- data/features/examples/switch-event/set_forward_entries.feature +90 -0
- data/features/support/hooks.rb +1 -0
- data/ruby/rake/c/dependency.rb +42 -0
- data/ruby/rake/c/library-task.rb +142 -0
- data/ruby/rake/c/shared-library-task.rb +38 -0
- data/ruby/rake/c/static-library-task.rb +32 -0
- data/ruby/trema/path.rb +1 -0
- data/ruby/trema/switch-event.c +647 -0
- data/{src/switch_manager/management_interface.h → ruby/trema/switch-event.h} +7 -21
- data/ruby/trema/trema.c +2 -0
- data/ruby/trema/version.rb +1 -1
- data/spec/spec_helper.rb +26 -2
- data/src/examples/switch_event_config/.gitignore +7 -0
- data/src/examples/switch_event_config/add_forward_entry.c +227 -0
- data/src/examples/switch_event_config/delete_forward_entry.c +226 -0
- data/src/examples/switch_event_config/dump_forward_entries.c +190 -0
- data/src/examples/switch_event_config/set_forward_entries.c +210 -0
- data/src/lib/event_forward_interface.c +783 -0
- data/src/lib/event_forward_interface.h +138 -0
- data/src/lib/trema.h +1 -0
- data/src/lib/utility.c +13 -1
- data/src/lib/utility.h +3 -0
- data/src/switch_manager/event_forward_entry_manipulation.c +120 -0
- data/src/switch_manager/event_forward_entry_manipulation.h +31 -0
- data/src/switch_manager/secure_channel_listener.c +23 -3
- data/src/switch_manager/switch.c +99 -29
- data/src/switch_manager/switch_manager.c +176 -3
- data/src/switch_manager/switch_manager.h +4 -0
- data/src/switch_manager/switch_option.c +30 -0
- data/src/switch_manager/switch_option.h +41 -0
- data/trema.gemspec +2 -1
- data/unittests/lib/event_forward_interface_test.c +1646 -0
- data/unittests/lib/utility_test.c +23 -1
- metadata +48 -10
@@ -0,0 +1,190 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 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
|
+
|
19
|
+
#include <getopt.h>
|
20
|
+
#include "trema.h"
|
21
|
+
|
22
|
+
|
23
|
+
static bool sw_manager = true;
|
24
|
+
static uint64_t dpid;
|
25
|
+
static enum efi_event_type type;
|
26
|
+
|
27
|
+
static struct option long_options[] = {
|
28
|
+
{ "manager", 0, NULL, 'm' },
|
29
|
+
{ "switch", 1, NULL, 's' },
|
30
|
+
{ "type", 1, NULL, 't' },
|
31
|
+
{ NULL, 0, NULL, 0 },
|
32
|
+
};
|
33
|
+
|
34
|
+
static char short_options[] = "ms:t:";
|
35
|
+
|
36
|
+
|
37
|
+
void
|
38
|
+
usage() {
|
39
|
+
printf(
|
40
|
+
"Dump OpenFlow Switch Manager/Daemon event forward entries.\n"
|
41
|
+
" Switch Manager: %s -m -t EVENT_TYPE\n"
|
42
|
+
" Switch Daemon : %s -s SWITCH_DPID -t EVENT_TYPE\n"
|
43
|
+
"\n"
|
44
|
+
" EVENT_TYPE:\n"
|
45
|
+
" -t, --type={vendor,packet_in,port_status,state_notify} Specify event type.\n"
|
46
|
+
" TREMA COMMON:\n"
|
47
|
+
" -n, --name=SERVICE_NAME service name\n"
|
48
|
+
" -d, --daemonize run in the background\n"
|
49
|
+
" -l, --logging_level=LEVEL set logging level\n"
|
50
|
+
" -g, --syslog output log messages to syslog\n"
|
51
|
+
" -f, --logging_facility=FACILITY set syslog facility\n"
|
52
|
+
" -h, --help display this help and exit\n"
|
53
|
+
, get_executable_name()
|
54
|
+
, get_executable_name()
|
55
|
+
);
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
static bool
|
60
|
+
parse_argument( int argc, char *argv[] ) {
|
61
|
+
|
62
|
+
bool type_specified = false;
|
63
|
+
|
64
|
+
int c;
|
65
|
+
while ( ( c = getopt_long( argc, argv, short_options, long_options, NULL ) ) != -1 ) {
|
66
|
+
switch ( c ) {
|
67
|
+
case 'm':
|
68
|
+
sw_manager = true;
|
69
|
+
break;
|
70
|
+
|
71
|
+
case 's':
|
72
|
+
sw_manager = false;
|
73
|
+
if ( !string_to_datapath_id( optarg, &dpid ) ) {
|
74
|
+
error( "Invalid dpid '%s' specified. ", optarg );
|
75
|
+
usage();
|
76
|
+
exit( EXIT_FAILURE );
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
break;
|
80
|
+
|
81
|
+
case 't': // add
|
82
|
+
type_specified = true;
|
83
|
+
if ( false ) {
|
84
|
+
}
|
85
|
+
else if ( strcasecmp( "vendor", optarg ) == 0 ) {
|
86
|
+
type = EVENT_FORWARD_TYPE_VENDOR;
|
87
|
+
}
|
88
|
+
else if ( strcasecmp( "packet_in", optarg ) == 0 ) {
|
89
|
+
type = EVENT_FORWARD_TYPE_PACKET_IN;
|
90
|
+
}
|
91
|
+
else if ( strcasecmp( "port_status", optarg ) == 0 ) {
|
92
|
+
type = EVENT_FORWARD_TYPE_PORT_STATUS;
|
93
|
+
}
|
94
|
+
else if ( strcasecmp( "state_notify", optarg ) == 0 ) {
|
95
|
+
type = EVENT_FORWARD_TYPE_STATE_NOTIFY;
|
96
|
+
}
|
97
|
+
else {
|
98
|
+
error( "Invalid type '%s' specified. Must e one of vendor, packet_in, port_status, or state_notify\n", optarg );
|
99
|
+
usage();
|
100
|
+
exit( EXIT_FAILURE );
|
101
|
+
return false;
|
102
|
+
}
|
103
|
+
break;
|
104
|
+
|
105
|
+
default:
|
106
|
+
error( "Encountered unknown option." );
|
107
|
+
usage();
|
108
|
+
exit( EXIT_FAILURE );
|
109
|
+
return false;
|
110
|
+
break;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
if ( !type_specified ) {
|
115
|
+
error( "Event Type was not specified with -t option.\n" );
|
116
|
+
usage();
|
117
|
+
exit( EXIT_FAILURE );
|
118
|
+
return false;
|
119
|
+
}
|
120
|
+
|
121
|
+
return true;
|
122
|
+
}
|
123
|
+
|
124
|
+
|
125
|
+
static void
|
126
|
+
timeout( void *user_data ) {
|
127
|
+
UNUSED( user_data );
|
128
|
+
|
129
|
+
error( "Request timed out." );
|
130
|
+
stop_trema();
|
131
|
+
exit( EXIT_FAILURE );
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
static void
|
136
|
+
current_result_callback( event_forward_operation_result result, void *user_data) {
|
137
|
+
UNUSED( user_data );
|
138
|
+
|
139
|
+
if ( result.result != EFI_OPERATION_SUCCEEDED ) {
|
140
|
+
error( "Operation Failed." );
|
141
|
+
stop_trema();
|
142
|
+
exit( EXIT_FAILURE );
|
143
|
+
}
|
144
|
+
else {
|
145
|
+
if ( result.n_services == 0 ) {
|
146
|
+
info( "Current service name list is empty.");
|
147
|
+
}
|
148
|
+
else {
|
149
|
+
info( "Current service name list:" );
|
150
|
+
unsigned i;
|
151
|
+
for ( i = 0; i < result.n_services; ++i ) {
|
152
|
+
info( " %s", result.services[ i ] );
|
153
|
+
}
|
154
|
+
}
|
155
|
+
stop_trema();
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
static void
|
161
|
+
send_efi_request( void ) {
|
162
|
+
info( "Dumping current service name list... " );
|
163
|
+
if ( sw_manager ) {
|
164
|
+
dump_switch_manager_event_forward_entries( type,
|
165
|
+
current_result_callback, NULL );
|
166
|
+
}
|
167
|
+
else {
|
168
|
+
dump_switch_event_forward_entries( dpid, type,
|
169
|
+
current_result_callback, NULL );
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
int
|
175
|
+
main( int argc, char *argv[] ) {
|
176
|
+
init_trema( &argc, &argv );
|
177
|
+
parse_argument( argc, argv );
|
178
|
+
|
179
|
+
init_event_forward_interface();
|
180
|
+
|
181
|
+
send_efi_request();
|
182
|
+
|
183
|
+
add_periodic_event_callback( 30, timeout, NULL );
|
184
|
+
|
185
|
+
start_trema();
|
186
|
+
|
187
|
+
finalize_event_forward_interface();
|
188
|
+
|
189
|
+
return 0;
|
190
|
+
}
|
@@ -0,0 +1,210 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 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
|
+
|
19
|
+
#include <getopt.h>
|
20
|
+
#include "trema.h"
|
21
|
+
|
22
|
+
|
23
|
+
static bool sw_manager = true;
|
24
|
+
static uint64_t dpid;
|
25
|
+
static enum efi_event_type type;
|
26
|
+
static list_element *service_names = NULL;
|
27
|
+
|
28
|
+
static struct option long_options[] = {
|
29
|
+
{ "manager", 0, NULL, 'm' },
|
30
|
+
{ "switch", 1, NULL, 's' },
|
31
|
+
{ "type", 1, NULL, 't' },
|
32
|
+
{ NULL, 0, NULL, 0 },
|
33
|
+
};
|
34
|
+
|
35
|
+
static char short_options[] = "ms:t:";
|
36
|
+
|
37
|
+
|
38
|
+
void
|
39
|
+
usage() {
|
40
|
+
printf(
|
41
|
+
"Set OpenFlow Switch Manager/Daemon event forward entries.\n"
|
42
|
+
" Switch Manager: %s -m -t EVENT_TYPE service_name1,service_name2,...\n"
|
43
|
+
" Switch Daemon : %s -s SWITCH_DPID -t EVENT_TYPE service_name1,service_name2,...\n"
|
44
|
+
"\n"
|
45
|
+
" EVENT_TYPE:\n"
|
46
|
+
" -t, --type={vendor,packet_in,port_status,state_notify} Specify event type.\n"
|
47
|
+
" TREMA COMMON:\n"
|
48
|
+
" -n, --name=SERVICE_NAME service name\n"
|
49
|
+
" -d, --daemonize run in the background\n"
|
50
|
+
" -l, --logging_level=LEVEL set logging level\n"
|
51
|
+
" -g, --syslog output log messages to syslog\n"
|
52
|
+
" -f, --logging_facility=FACILITY set syslog facility\n"
|
53
|
+
" -h, --help display this help and exit\n"
|
54
|
+
, get_executable_name()
|
55
|
+
, get_executable_name()
|
56
|
+
);
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
static bool
|
61
|
+
parse_argument( int argc, char *argv[] ) {
|
62
|
+
|
63
|
+
bool type_specified = false;
|
64
|
+
|
65
|
+
create_list( &service_names );
|
66
|
+
|
67
|
+
int c;
|
68
|
+
while ( ( c = getopt_long( argc, argv, short_options, long_options, NULL ) ) != -1 ) {
|
69
|
+
switch ( c ) {
|
70
|
+
case 'm':
|
71
|
+
sw_manager = true;
|
72
|
+
break;
|
73
|
+
|
74
|
+
case 's':
|
75
|
+
sw_manager = false;
|
76
|
+
if ( !string_to_datapath_id( optarg, &dpid ) ) {
|
77
|
+
error( "Invalid dpid '%s' specified. ", optarg );
|
78
|
+
usage();
|
79
|
+
exit( EXIT_FAILURE );
|
80
|
+
return false;
|
81
|
+
}
|
82
|
+
break;
|
83
|
+
|
84
|
+
case 't': // add
|
85
|
+
type_specified = true;
|
86
|
+
if ( false ) {
|
87
|
+
}
|
88
|
+
else if ( strcasecmp( "vendor", optarg ) == 0 ) {
|
89
|
+
type = EVENT_FORWARD_TYPE_VENDOR;
|
90
|
+
}
|
91
|
+
else if ( strcasecmp( "packet_in", optarg ) == 0 ) {
|
92
|
+
type = EVENT_FORWARD_TYPE_PACKET_IN;
|
93
|
+
}
|
94
|
+
else if ( strcasecmp( "port_status", optarg ) == 0 ) {
|
95
|
+
type = EVENT_FORWARD_TYPE_PORT_STATUS;
|
96
|
+
}
|
97
|
+
else if ( strcasecmp( "state_notify", optarg ) == 0 ) {
|
98
|
+
type = EVENT_FORWARD_TYPE_STATE_NOTIFY;
|
99
|
+
}
|
100
|
+
else {
|
101
|
+
error( "Invalid type '%s' specified. Must e one of vendor, packet_in, port_status, or state_notify\n", optarg );
|
102
|
+
usage();
|
103
|
+
exit( EXIT_FAILURE );
|
104
|
+
return false;
|
105
|
+
}
|
106
|
+
break;
|
107
|
+
|
108
|
+
default:
|
109
|
+
error( "Encountered unknown option." );
|
110
|
+
usage();
|
111
|
+
exit( EXIT_FAILURE );
|
112
|
+
return false;
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
if ( !type_specified ) {
|
118
|
+
error( "Event Type was not specified with -t option.\n" );
|
119
|
+
usage();
|
120
|
+
exit( EXIT_FAILURE );
|
121
|
+
return false;
|
122
|
+
}
|
123
|
+
|
124
|
+
if ( optind >= argc ) {
|
125
|
+
error( "Service names were not specified.\n" );
|
126
|
+
usage();
|
127
|
+
exit( EXIT_FAILURE );
|
128
|
+
return false;
|
129
|
+
}
|
130
|
+
|
131
|
+
int i;
|
132
|
+
for ( i = optind; i < argc; ++i ) {
|
133
|
+
char *service_name = strtok( argv[ i ], "," );
|
134
|
+
if ( service_name != NULL ) {
|
135
|
+
append_to_tail( &service_names, service_name );
|
136
|
+
while ( ( service_name = strtok( NULL, "," ) ) != NULL ) {
|
137
|
+
append_to_tail( &service_names, service_name );
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
return true;
|
143
|
+
}
|
144
|
+
|
145
|
+
|
146
|
+
static void
|
147
|
+
timeout( void *user_data ) {
|
148
|
+
UNUSED( user_data );
|
149
|
+
|
150
|
+
error( "Request timed out." );
|
151
|
+
stop_trema();
|
152
|
+
exit( EXIT_FAILURE );
|
153
|
+
}
|
154
|
+
|
155
|
+
|
156
|
+
static void
|
157
|
+
update_result_callback( event_forward_operation_result result, void *user_data) {
|
158
|
+
UNUSED( user_data );
|
159
|
+
|
160
|
+
if ( result.result != EFI_OPERATION_SUCCEEDED ) {
|
161
|
+
error( "Operation Failed." );
|
162
|
+
stop_trema();
|
163
|
+
exit( EXIT_FAILURE );
|
164
|
+
}
|
165
|
+
else {
|
166
|
+
if ( result.n_services == 0 ) {
|
167
|
+
info( "Updated service name list is empty.");
|
168
|
+
}
|
169
|
+
else {
|
170
|
+
info( "Updated service name list:" );
|
171
|
+
unsigned i;
|
172
|
+
for ( i = 0; i < result.n_services; ++i ) {
|
173
|
+
info( " %s", result.services[ i ] );
|
174
|
+
}
|
175
|
+
}
|
176
|
+
stop_trema();
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
static void
|
182
|
+
send_efi_request( void ) {
|
183
|
+
info( "Setting service names... " );
|
184
|
+
if ( sw_manager ) {
|
185
|
+
set_switch_manager_event_forward_entries( type, service_names,
|
186
|
+
update_result_callback, NULL );
|
187
|
+
} else {
|
188
|
+
set_switch_event_forward_entries( dpid, type, service_names,
|
189
|
+
update_result_callback, NULL );
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
|
194
|
+
int
|
195
|
+
main( int argc, char *argv[] ) {
|
196
|
+
init_trema( &argc, &argv );
|
197
|
+
parse_argument( argc, argv );
|
198
|
+
|
199
|
+
init_event_forward_interface();
|
200
|
+
|
201
|
+
send_efi_request();
|
202
|
+
|
203
|
+
add_periodic_event_callback( 30, timeout, NULL );
|
204
|
+
|
205
|
+
start_trema();
|
206
|
+
|
207
|
+
finalize_event_forward_interface();
|
208
|
+
|
209
|
+
return 0;
|
210
|
+
}
|
@@ -0,0 +1,783 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 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
|
+
#include <assert.h>
|
19
|
+
#include <sys/types.h>
|
20
|
+
#include <unistd.h>
|
21
|
+
#include "trema.h"
|
22
|
+
#include "trema_wrapper.h"
|
23
|
+
#include "event_forward_interface.h"
|
24
|
+
|
25
|
+
|
26
|
+
static char *efi_queue_name = NULL;
|
27
|
+
|
28
|
+
|
29
|
+
// txid -> all_sw_tx;
|
30
|
+
static hash_table *efi_tx_table = NULL;
|
31
|
+
|
32
|
+
|
33
|
+
struct event_forward_operation_request_param {
|
34
|
+
event_forward_entry_operation_callback callback;
|
35
|
+
void *user_data;
|
36
|
+
};
|
37
|
+
|
38
|
+
|
39
|
+
struct event_forward_operation_to_all_request_param {
|
40
|
+
bool add;
|
41
|
+
enum efi_event_type type;
|
42
|
+
char *service_name;
|
43
|
+
event_forward_entry_to_all_callback callback;
|
44
|
+
void *user_data;
|
45
|
+
};
|
46
|
+
|
47
|
+
|
48
|
+
struct sw_list_request_param {
|
49
|
+
switch_list_request_callback callback;
|
50
|
+
void *user_data;
|
51
|
+
};
|
52
|
+
|
53
|
+
|
54
|
+
typedef struct all_sw_tx {
|
55
|
+
uint32_t txid;
|
56
|
+
hash_table *waiting_dpid;
|
57
|
+
enum efi_result tx_result;
|
58
|
+
|
59
|
+
struct event_forward_operation_to_all_request_param *request_param;
|
60
|
+
} all_sw_tx;
|
61
|
+
|
62
|
+
|
63
|
+
struct txinfo {
|
64
|
+
uint64_t dpid;
|
65
|
+
uint32_t txid;
|
66
|
+
};
|
67
|
+
|
68
|
+
|
69
|
+
static void
|
70
|
+
xfree_event_forward_operation_to_all_request_param( struct event_forward_operation_to_all_request_param *param ) {
|
71
|
+
xfree( param->service_name );
|
72
|
+
param->service_name = NULL;
|
73
|
+
xfree( param );
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
// foreach_hash helper function
|
78
|
+
static void
|
79
|
+
xfree_dpid( void *key, void *value, void *user_data ) {
|
80
|
+
UNUSED( value );
|
81
|
+
UNUSED( user_data );
|
82
|
+
xfree( key );
|
83
|
+
}
|
84
|
+
|
85
|
+
|
86
|
+
static void
|
87
|
+
xfree_all_sw_tx( all_sw_tx *tx ) {
|
88
|
+
struct event_forward_operation_to_all_request_param *param = tx->request_param;
|
89
|
+
xfree_event_forward_operation_to_all_request_param( param );
|
90
|
+
tx->request_param = NULL;
|
91
|
+
|
92
|
+
foreach_hash( tx->waiting_dpid, xfree_dpid, NULL );
|
93
|
+
delete_hash( tx->waiting_dpid );
|
94
|
+
tx->waiting_dpid = NULL;
|
95
|
+
xfree( tx );
|
96
|
+
}
|
97
|
+
|
98
|
+
|
99
|
+
const char*
|
100
|
+
_get_efi_queue_name( void ) {
|
101
|
+
return efi_queue_name;
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
buffer*
|
106
|
+
create_event_forward_operation_request( buffer *buf, enum efi_event_type type, list_element *service_list ) {
|
107
|
+
if ( buf == NULL ) {
|
108
|
+
buf = alloc_buffer_with_length( sizeof( event_forward_operation_request ) + MESSENGER_SERVICE_NAME_LENGTH );
|
109
|
+
}
|
110
|
+
event_forward_operation_request *req = append_back_buffer( buf, sizeof( event_forward_operation_request ) );
|
111
|
+
memset( req, 0, sizeof( event_forward_operation_request ) );
|
112
|
+
|
113
|
+
req->type = ( uint8_t ) type;
|
114
|
+
|
115
|
+
size_t request_head_offset = sizeof( event_forward_operation_request );
|
116
|
+
uint32_t n_services = 0;
|
117
|
+
if ( service_list != NULL ) {
|
118
|
+
for ( list_element *e = service_list; e != NULL; e = e->next ) {
|
119
|
+
const size_t len = strlen( e->data );
|
120
|
+
char *dst = append_back_buffer( buf, len + 1 );
|
121
|
+
req = ( event_forward_operation_request * )( dst - request_head_offset );
|
122
|
+
request_head_offset += len + 1;
|
123
|
+
strcpy( dst, e->data );
|
124
|
+
dst[ len ] = '\0';
|
125
|
+
++n_services;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
req->n_services = htonl( n_services );
|
130
|
+
return buf;
|
131
|
+
}
|
132
|
+
|
133
|
+
|
134
|
+
buffer*
|
135
|
+
create_event_forward_operation_reply( enum efi_event_type type, enum efi_result result, list_element *service_list ) {
|
136
|
+
buffer *buf = alloc_buffer_with_length( sizeof( event_forward_operation_reply ) + MESSENGER_SERVICE_NAME_LENGTH );
|
137
|
+
event_forward_operation_reply *rep = append_back_buffer( buf, sizeof( event_forward_operation_reply ) );
|
138
|
+
memset( rep, 0, sizeof( event_forward_operation_reply ) );
|
139
|
+
|
140
|
+
rep->type = ( uint8_t ) type;
|
141
|
+
rep->result = ( uint8_t ) result;
|
142
|
+
|
143
|
+
size_t reply_head_offset = sizeof( event_forward_operation_reply );
|
144
|
+
uint32_t n_services = 0;
|
145
|
+
if ( service_list != NULL ) {
|
146
|
+
for ( list_element *e = service_list; e != NULL; e = e->next ) {
|
147
|
+
const size_t len = strlen( e->data );
|
148
|
+
char *dst = append_back_buffer( buf, len + 1 );
|
149
|
+
rep = ( event_forward_operation_reply * )( dst - reply_head_offset );
|
150
|
+
reply_head_offset += len + 1;
|
151
|
+
strcpy( dst, e->data );
|
152
|
+
dst[ len ] = '\0';
|
153
|
+
++n_services;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
rep->n_services = htonl( n_services );
|
158
|
+
return buf;
|
159
|
+
}
|
160
|
+
|
161
|
+
|
162
|
+
static void
|
163
|
+
handle_event_forward_operation_reply( management_application_reply *reply, size_t length, struct event_forward_operation_request_param *param ) {
|
164
|
+
event_forward_operation_result result;
|
165
|
+
result.result = EFI_OPERATION_FAILED;
|
166
|
+
result.n_services = 0;
|
167
|
+
result.services = NULL;
|
168
|
+
|
169
|
+
event_forward_operation_reply *efi_reply = ( event_forward_operation_reply * ) reply->data;
|
170
|
+
efi_reply->n_services = ntohl( efi_reply->n_services );
|
171
|
+
|
172
|
+
if ( reply->header.status == MANAGEMENT_REQUEST_FAILED ) {
|
173
|
+
warn( "Management request failed." );
|
174
|
+
result.result = EFI_OPERATION_FAILED;
|
175
|
+
if ( param->callback != NULL ) {
|
176
|
+
param->callback( result, param->user_data );
|
177
|
+
}
|
178
|
+
return;
|
179
|
+
}
|
180
|
+
|
181
|
+
switch ( efi_reply->result ) {
|
182
|
+
case EFI_OPERATION_SUCCEEDED:
|
183
|
+
result.result = EFI_OPERATION_SUCCEEDED;
|
184
|
+
break;
|
185
|
+
case EFI_OPERATION_FAILED:
|
186
|
+
result.result = EFI_OPERATION_FAILED;
|
187
|
+
break;
|
188
|
+
default:
|
189
|
+
warn( "Unknown result type %#x. Translating as FAILED.", efi_reply->result );
|
190
|
+
result.result = EFI_OPERATION_FAILED;
|
191
|
+
break;
|
192
|
+
}
|
193
|
+
|
194
|
+
if ( result.result == EFI_OPERATION_FAILED ) {
|
195
|
+
if ( param->callback != NULL ) {
|
196
|
+
param->callback( result, param->user_data );
|
197
|
+
}
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
|
201
|
+
const size_t service_list_len = length
|
202
|
+
- offsetof( management_application_reply, data )
|
203
|
+
- offsetof( event_forward_operation_reply, service_list );
|
204
|
+
|
205
|
+
// null terminate input to avoid overrun.
|
206
|
+
efi_reply->service_list[ service_list_len ] = '\0';
|
207
|
+
|
208
|
+
const uint32_t n_services_expected = efi_reply->n_services;
|
209
|
+
result.services = xcalloc( n_services_expected, sizeof( char * ) );
|
210
|
+
|
211
|
+
result.n_services = 0;
|
212
|
+
const char *next_name = efi_reply->service_list;
|
213
|
+
while ( next_name < &efi_reply->service_list[ service_list_len ] ) {
|
214
|
+
const size_t name_len = strlen( next_name );
|
215
|
+
if ( name_len > 0 ) {
|
216
|
+
if ( result.n_services < n_services_expected ) {
|
217
|
+
result.services[ result.n_services++ ] = next_name;
|
218
|
+
}
|
219
|
+
else {
|
220
|
+
warn( "Expected %d name(s), but found more service name. Ignoring '%s'.", n_services_expected, next_name );
|
221
|
+
}
|
222
|
+
}
|
223
|
+
else {
|
224
|
+
warn( "Encountered empty service name." );
|
225
|
+
}
|
226
|
+
next_name += name_len + 1;
|
227
|
+
}
|
228
|
+
|
229
|
+
if ( param->callback != NULL ) {
|
230
|
+
param->callback( result, param->user_data );
|
231
|
+
}
|
232
|
+
xfree( result.services );
|
233
|
+
}
|
234
|
+
|
235
|
+
|
236
|
+
static void
|
237
|
+
handle_get_switch_list_reply( management_application_reply *reply, size_t length, struct sw_list_request_param *param ) {
|
238
|
+
|
239
|
+
if ( reply->header.status == MANAGEMENT_REQUEST_FAILED ) {
|
240
|
+
warn( "Management request failed." );
|
241
|
+
if ( param->callback != NULL ) {
|
242
|
+
param->callback( NULL, 0, param->user_data );
|
243
|
+
}
|
244
|
+
return;
|
245
|
+
}
|
246
|
+
|
247
|
+
uint64_t *dpids = ( uint64_t * ) reply->data;
|
248
|
+
const size_t data_bytes = length - sizeof( management_application_reply );
|
249
|
+
if ( data_bytes % sizeof( uint64_t ) != 0 ) {
|
250
|
+
warn( "data length was not multiple of uint64_t size %zu", data_bytes );
|
251
|
+
}
|
252
|
+
const size_t n_dpids = data_bytes / sizeof( uint64_t );
|
253
|
+
|
254
|
+
for ( size_t i = 0 ; i < n_dpids ; ++i ) {
|
255
|
+
dpids[ i ] = ntohll( dpids[ i ] );
|
256
|
+
}
|
257
|
+
|
258
|
+
if ( param->callback != NULL ) {
|
259
|
+
param->callback( dpids, n_dpids, param->user_data );
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
|
264
|
+
static void
|
265
|
+
handle_efi_reply( uint16_t tag, void *data, size_t length, void *user_data ) {
|
266
|
+
|
267
|
+
debug( "handle_efi_reply: tag=%#x, data=%p, length=%zu, user_data=%p", tag, data, length, user_data );
|
268
|
+
|
269
|
+
if ( tag != MESSENGER_MANAGEMENT_REPLY ) {
|
270
|
+
error( "Unexpected message received tag=%#x", tag );
|
271
|
+
return;
|
272
|
+
}
|
273
|
+
if ( data == NULL ) {
|
274
|
+
error( "Received reply had no data" );
|
275
|
+
return;
|
276
|
+
}
|
277
|
+
if ( length < sizeof( management_application_reply ) ) {
|
278
|
+
error( "Data length too short %zu. expecting >= %zu", length, sizeof( management_application_reply ) );
|
279
|
+
return;
|
280
|
+
}
|
281
|
+
|
282
|
+
management_application_reply *reply = data;
|
283
|
+
if ( ntohs( reply->header.type ) != MANAGEMENT_APPLICATION_REPLY ) {
|
284
|
+
error( "Invalid reply type %#x, expecting MANAGEMENT_APPLICATION_REPLY:%#x", ntohs( reply->header.type ), MANAGEMENT_APPLICATION_REPLY );
|
285
|
+
return;
|
286
|
+
}
|
287
|
+
const uint32_t command = ntohl( reply->application_id );
|
288
|
+
|
289
|
+
// check command validity
|
290
|
+
switch ( command ) {
|
291
|
+
case EVENT_FORWARD_ENTRY_ADD:
|
292
|
+
case EVENT_FORWARD_ENTRY_DELETE:
|
293
|
+
case EVENT_FORWARD_ENTRY_DUMP:
|
294
|
+
case EVENT_FORWARD_ENTRY_SET:
|
295
|
+
{
|
296
|
+
struct event_forward_operation_request_param *param = user_data;
|
297
|
+
handle_event_forward_operation_reply( reply, length, param );
|
298
|
+
xfree( param );
|
299
|
+
return;
|
300
|
+
}
|
301
|
+
break;
|
302
|
+
|
303
|
+
case EFI_GET_SWLIST:
|
304
|
+
{
|
305
|
+
struct sw_list_request_param *param = user_data;
|
306
|
+
handle_get_switch_list_reply( reply, length, param );
|
307
|
+
xfree( param );
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
break;
|
311
|
+
|
312
|
+
default:
|
313
|
+
warn( "Invalid command/application_id: %#x", command );
|
314
|
+
return;
|
315
|
+
break;
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
|
320
|
+
bool
|
321
|
+
init_event_forward_interface( void ) {
|
322
|
+
if ( efi_queue_name != NULL ) {
|
323
|
+
warn( "already initialized." );
|
324
|
+
return false;
|
325
|
+
}
|
326
|
+
|
327
|
+
efi_queue_name = xcalloc( 1, MESSENGER_SERVICE_NAME_LENGTH );
|
328
|
+
|
329
|
+
int chWrite = snprintf( efi_queue_name, MESSENGER_SERVICE_NAME_LENGTH,
|
330
|
+
"%s-efic-%d", get_trema_name(), trema_getpid() );
|
331
|
+
if ( chWrite >= MESSENGER_SERVICE_NAME_LENGTH ) {
|
332
|
+
snprintf( efi_queue_name, MESSENGER_SERVICE_NAME_LENGTH,
|
333
|
+
"efic-%d", trema_getpid() );
|
334
|
+
}
|
335
|
+
|
336
|
+
// management reply handler
|
337
|
+
add_message_replied_callback( efi_queue_name, handle_efi_reply );
|
338
|
+
|
339
|
+
efi_tx_table = create_hash( compare_uint32, hash_uint32 );
|
340
|
+
return true;
|
341
|
+
}
|
342
|
+
|
343
|
+
|
344
|
+
static void
|
345
|
+
maybe_init_event_forward_interface( void ) {
|
346
|
+
if ( efi_queue_name == NULL ) {
|
347
|
+
info( "Initializing at maybe_init_event_forward_interface()" );
|
348
|
+
init_event_forward_interface();
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
|
353
|
+
void
|
354
|
+
_cleanup_tx_table() {
|
355
|
+
hash_iterator it;
|
356
|
+
init_hash_iterator( efi_tx_table, &it );
|
357
|
+
hash_entry *e = NULL;
|
358
|
+
while ( ( e = iterate_hash_next( &it ) ) != NULL ) {
|
359
|
+
all_sw_tx *tx = e->value;
|
360
|
+
warn( "txid:%#x was left behind.", tx->txid );
|
361
|
+
|
362
|
+
delete_hash_entry( efi_tx_table, &tx->txid );
|
363
|
+
xfree_all_sw_tx( tx );
|
364
|
+
}
|
365
|
+
}
|
366
|
+
|
367
|
+
|
368
|
+
bool
|
369
|
+
finalize_event_forward_interface( void ) {
|
370
|
+
if ( efi_queue_name == NULL ) {
|
371
|
+
warn( "already finalized." );
|
372
|
+
return false;
|
373
|
+
}
|
374
|
+
delete_message_replied_callback( efi_queue_name, handle_efi_reply );
|
375
|
+
|
376
|
+
xfree( efi_queue_name );
|
377
|
+
efi_queue_name = NULL;
|
378
|
+
|
379
|
+
_cleanup_tx_table();
|
380
|
+
delete_hash( efi_tx_table );
|
381
|
+
efi_tx_table = NULL;
|
382
|
+
|
383
|
+
return true;
|
384
|
+
}
|
385
|
+
|
386
|
+
|
387
|
+
static bool
|
388
|
+
send_efi_event_config_request( const char *service_name, enum switch_management_command command, enum efi_event_type type, list_element *service_list, event_forward_entry_operation_callback callback, void *user_data ) {
|
389
|
+
maybe_init_event_forward_interface();
|
390
|
+
if ( service_name == NULL ) {
|
391
|
+
return false;
|
392
|
+
}
|
393
|
+
switch( command ) {
|
394
|
+
case EVENT_FORWARD_ENTRY_ADD:
|
395
|
+
case EVENT_FORWARD_ENTRY_DELETE:
|
396
|
+
case EVENT_FORWARD_ENTRY_DUMP:
|
397
|
+
case EVENT_FORWARD_ENTRY_SET:
|
398
|
+
// do nothing;
|
399
|
+
break;
|
400
|
+
default:
|
401
|
+
return false;
|
402
|
+
}
|
403
|
+
|
404
|
+
buffer *all_req = alloc_buffer_with_length( sizeof( management_application_request ) + sizeof( event_forward_operation_request ) + MESSENGER_SERVICE_NAME_LENGTH );
|
405
|
+
|
406
|
+
management_application_request *apreq = append_back_buffer( all_req, sizeof( management_application_request ) );
|
407
|
+
apreq->header.type = htons( MANAGEMENT_APPLICATION_REQUEST );
|
408
|
+
apreq->application_id = htonl( command );
|
409
|
+
create_event_forward_operation_request( all_req, type, service_list );
|
410
|
+
apreq = all_req->data;
|
411
|
+
apreq->header.length = htonl( ( uint32_t ) all_req->length );
|
412
|
+
|
413
|
+
struct event_forward_operation_request_param *param = xcalloc( 1, sizeof( struct event_forward_operation_request_param ) );
|
414
|
+
param->callback = callback;
|
415
|
+
param->user_data = user_data;
|
416
|
+
|
417
|
+
bool sent = send_request_message( service_name, efi_queue_name, MESSENGER_MANAGEMENT_REQUEST,
|
418
|
+
all_req->data, all_req->length, param );
|
419
|
+
if ( !sent ) {
|
420
|
+
xfree( param );
|
421
|
+
}
|
422
|
+
free_buffer( all_req );
|
423
|
+
|
424
|
+
return sent;
|
425
|
+
}
|
426
|
+
|
427
|
+
|
428
|
+
// Low level API for switch manager
|
429
|
+
bool
|
430
|
+
set_switch_manager_event_forward_entries( enum efi_event_type type, list_element *service_list, event_forward_entry_operation_callback callback, void *user_data ) {
|
431
|
+
const char switch_manager[] = "switch_manager.m";
|
432
|
+
return send_efi_event_config_request( switch_manager, EVENT_FORWARD_ENTRY_SET, type, service_list, callback, user_data );
|
433
|
+
}
|
434
|
+
|
435
|
+
|
436
|
+
bool
|
437
|
+
add_switch_manager_event_forward_entry( enum efi_event_type type, const char *service_name, event_forward_entry_operation_callback callback, void *user_data ) {
|
438
|
+
const char switch_manager[] = "switch_manager.m";
|
439
|
+
list_element service_list;
|
440
|
+
service_list.next = NULL;
|
441
|
+
#pragma GCC diagnostic push
|
442
|
+
#pragma GCC diagnostic ignored "-Wcast-qual"
|
443
|
+
service_list.data = ( void * ) service_name;
|
444
|
+
#pragma GCC diagnostic pop
|
445
|
+
return send_efi_event_config_request( switch_manager, EVENT_FORWARD_ENTRY_ADD, type, &service_list, callback, user_data );
|
446
|
+
}
|
447
|
+
|
448
|
+
|
449
|
+
bool
|
450
|
+
delete_switch_manager_event_forward_entry( enum efi_event_type type, const char *service_name, event_forward_entry_operation_callback callback, void *user_data ) {
|
451
|
+
const char switch_manager[] = "switch_manager.m";
|
452
|
+
list_element service_list;
|
453
|
+
service_list.next = NULL;
|
454
|
+
#pragma GCC diagnostic push
|
455
|
+
#pragma GCC diagnostic ignored "-Wcast-qual"
|
456
|
+
service_list.data = ( void * ) service_name;
|
457
|
+
#pragma GCC diagnostic pop
|
458
|
+
return send_efi_event_config_request( switch_manager, EVENT_FORWARD_ENTRY_DELETE, type, &service_list, callback, user_data );
|
459
|
+
}
|
460
|
+
|
461
|
+
|
462
|
+
bool
|
463
|
+
dump_switch_manager_event_forward_entries( enum efi_event_type type, event_forward_entry_operation_callback callback, void *user_data ) {
|
464
|
+
const char switch_manager[] = "switch_manager.m";
|
465
|
+
return send_efi_event_config_request( switch_manager, EVENT_FORWARD_ENTRY_DUMP, type, NULL, callback, user_data );
|
466
|
+
}
|
467
|
+
|
468
|
+
|
469
|
+
bool
|
470
|
+
set_switch_event_forward_entries( uint64_t dpid, enum efi_event_type type, list_element *service_list, event_forward_entry_operation_callback callback, void *user_data ) {
|
471
|
+
char switch_name[ MESSENGER_SERVICE_NAME_LENGTH ];
|
472
|
+
snprintf( switch_name, MESSENGER_SERVICE_NAME_LENGTH, "switch.%#" PRIx64 ".m", dpid );
|
473
|
+
return send_efi_event_config_request( switch_name, EVENT_FORWARD_ENTRY_SET, type, service_list, callback, user_data );
|
474
|
+
}
|
475
|
+
|
476
|
+
|
477
|
+
bool
|
478
|
+
add_switch_event_forward_entry( uint64_t dpid, enum efi_event_type type, const char *service_name, event_forward_entry_operation_callback callback, void *user_data ) {
|
479
|
+
char switch_name[ MESSENGER_SERVICE_NAME_LENGTH ];
|
480
|
+
snprintf( switch_name, MESSENGER_SERVICE_NAME_LENGTH, "switch.%#" PRIx64 ".m", dpid );
|
481
|
+
list_element service_list;
|
482
|
+
service_list.next = NULL;
|
483
|
+
#pragma GCC diagnostic push
|
484
|
+
#pragma GCC diagnostic ignored "-Wcast-qual"
|
485
|
+
service_list.data = ( void * ) service_name;
|
486
|
+
#pragma GCC diagnostic pop
|
487
|
+
return send_efi_event_config_request( switch_name, EVENT_FORWARD_ENTRY_ADD, type, &service_list, callback, user_data );
|
488
|
+
}
|
489
|
+
|
490
|
+
|
491
|
+
bool
|
492
|
+
delete_switch_event_forward_entry( uint64_t dpid, enum efi_event_type type, const char *service_name, event_forward_entry_operation_callback callback, void *user_data ) {
|
493
|
+
char switch_name[ MESSENGER_SERVICE_NAME_LENGTH ];
|
494
|
+
snprintf( switch_name, MESSENGER_SERVICE_NAME_LENGTH, "switch.%#" PRIx64 ".m", dpid );
|
495
|
+
list_element service_list;
|
496
|
+
service_list.next = NULL;
|
497
|
+
#pragma GCC diagnostic push
|
498
|
+
#pragma GCC diagnostic ignored "-Wcast-qual"
|
499
|
+
service_list.data = ( void * ) service_name;
|
500
|
+
#pragma GCC diagnostic pop
|
501
|
+
return send_efi_event_config_request( switch_name, EVENT_FORWARD_ENTRY_DELETE, type, &service_list, callback, user_data );
|
502
|
+
}
|
503
|
+
|
504
|
+
|
505
|
+
bool
|
506
|
+
dump_switch_event_forward_entries( uint64_t dpid, enum efi_event_type type, event_forward_entry_operation_callback callback, void *user_data ) {
|
507
|
+
char switch_name[ MESSENGER_SERVICE_NAME_LENGTH ];
|
508
|
+
snprintf( switch_name, MESSENGER_SERVICE_NAME_LENGTH, "switch.%#" PRIx64 ".m", dpid );
|
509
|
+
return send_efi_event_config_request( switch_name, EVENT_FORWARD_ENTRY_DUMP, type, NULL, callback, user_data );
|
510
|
+
}
|
511
|
+
|
512
|
+
|
513
|
+
bool
|
514
|
+
send_efi_switch_list_request( switch_list_request_callback callback, void *user_data ) {
|
515
|
+
maybe_init_event_forward_interface();
|
516
|
+
if ( callback == NULL ) {
|
517
|
+
return false;
|
518
|
+
}
|
519
|
+
|
520
|
+
management_application_request req;
|
521
|
+
req.header.type = htons( MANAGEMENT_APPLICATION_REQUEST );
|
522
|
+
req.header.length = htonl( ( uint32_t ) sizeof( management_application_request ) );
|
523
|
+
req.application_id = htonl( EFI_GET_SWLIST );
|
524
|
+
|
525
|
+
struct sw_list_request_param *param = xcalloc( 1, sizeof( struct sw_list_request_param ) );
|
526
|
+
param->callback = callback;
|
527
|
+
param->user_data = user_data;
|
528
|
+
|
529
|
+
bool sent_ok = send_request_message( "switch_manager.m", efi_queue_name, MESSENGER_MANAGEMENT_REQUEST,
|
530
|
+
&req, sizeof( management_application_request ), param );
|
531
|
+
if ( !sent_ok ) {
|
532
|
+
xfree( param );
|
533
|
+
}
|
534
|
+
|
535
|
+
return sent_ok;
|
536
|
+
}
|
537
|
+
|
538
|
+
|
539
|
+
static uint32_t
|
540
|
+
get_txid() {
|
541
|
+
static uint32_t txid = 0;
|
542
|
+
return ++txid;
|
543
|
+
}
|
544
|
+
|
545
|
+
|
546
|
+
static bool
|
547
|
+
hash_table_is_empty( hash_table *tbl ) {
|
548
|
+
hash_iterator it;
|
549
|
+
init_hash_iterator( tbl, &it );
|
550
|
+
return ( iterate_hash_next( &it ) == NULL );
|
551
|
+
}
|
552
|
+
|
553
|
+
|
554
|
+
static bool
|
555
|
+
check_tx_result_and_respond( all_sw_tx *tx ) {
|
556
|
+
if ( tx->tx_result == EFI_OPERATION_FAILED ) {
|
557
|
+
struct event_forward_operation_to_all_request_param *all_param = tx->request_param;
|
558
|
+
if ( all_param->callback != NULL ) {
|
559
|
+
all_param->callback( tx->tx_result, all_param->user_data );
|
560
|
+
}
|
561
|
+
|
562
|
+
info( "txid %#x completed with failure.", tx->txid );
|
563
|
+
// remove and cleanup tx
|
564
|
+
delete_hash_entry( efi_tx_table, &tx->txid );
|
565
|
+
xfree_all_sw_tx( tx );
|
566
|
+
return true;
|
567
|
+
}
|
568
|
+
return false;
|
569
|
+
}
|
570
|
+
|
571
|
+
|
572
|
+
void
|
573
|
+
_switch_response_timeout( void *user_data ) {
|
574
|
+
struct txinfo *txinfo = user_data;
|
575
|
+
const uint64_t dpid = txinfo->dpid;
|
576
|
+
const uint32_t txid = txinfo->txid;
|
577
|
+
// xfree( txinfo ); // cannot free since _switch_response_handler may be called later.
|
578
|
+
txinfo = NULL;
|
579
|
+
debug( "txid %#x switch %#" PRIx64 " time out. called", txid, dpid );
|
580
|
+
|
581
|
+
all_sw_tx *tx = lookup_hash_entry( efi_tx_table, &txid );
|
582
|
+
if ( tx == NULL ) {
|
583
|
+
// transaction already failed. Do nothing.
|
584
|
+
return;
|
585
|
+
}
|
586
|
+
|
587
|
+
uint64_t *dpid_in_list = lookup_hash_entry( tx->waiting_dpid, &dpid );
|
588
|
+
if ( dpid_in_list != NULL ) {
|
589
|
+
info( "txid %#x switch %#" PRIx64 " timed out.", txid, dpid );
|
590
|
+
delete_hash_entry( tx->waiting_dpid, &dpid );
|
591
|
+
xfree( dpid_in_list );
|
592
|
+
tx->tx_result = EFI_OPERATION_FAILED;
|
593
|
+
}
|
594
|
+
|
595
|
+
check_tx_result_and_respond( tx );
|
596
|
+
}
|
597
|
+
|
598
|
+
|
599
|
+
void
|
600
|
+
_switch_response_handler( event_forward_operation_result result, void *user_data ) {
|
601
|
+
struct txinfo *txinfo = user_data;
|
602
|
+
const uint64_t dpid = txinfo->dpid;
|
603
|
+
const uint32_t txid = txinfo->txid;
|
604
|
+
delete_timer_event( _switch_response_timeout, txinfo );
|
605
|
+
xfree( txinfo );
|
606
|
+
txinfo = NULL;
|
607
|
+
debug( "txid %#x switch %#" PRIx64 " response.", txid, dpid );
|
608
|
+
|
609
|
+
all_sw_tx *tx = lookup_hash_entry( efi_tx_table, &txid );
|
610
|
+
if ( tx == NULL ) {
|
611
|
+
// transaction already failed. Do nothing.
|
612
|
+
return;
|
613
|
+
}
|
614
|
+
|
615
|
+
uint64_t *dpid_in_list = lookup_hash_entry( tx->waiting_dpid, &dpid );
|
616
|
+
if ( dpid_in_list == NULL ) {
|
617
|
+
// probably timed out. Do nothing.
|
618
|
+
return;
|
619
|
+
}
|
620
|
+
delete_hash_entry( tx->waiting_dpid, &dpid );
|
621
|
+
xfree( dpid_in_list );
|
622
|
+
dpid_in_list = NULL;
|
623
|
+
|
624
|
+
if ( result.result == EFI_OPERATION_FAILED ) {
|
625
|
+
warn( "txid %#x Setting event forwarding entry to switch %#" PRIx64 " failed.", txid, dpid );
|
626
|
+
tx->tx_result = EFI_OPERATION_FAILED;
|
627
|
+
}
|
628
|
+
|
629
|
+
bool tx_ended = check_tx_result_and_respond( tx );
|
630
|
+
if ( tx_ended ) return;
|
631
|
+
|
632
|
+
struct event_forward_operation_to_all_request_param *all_param = tx->request_param;
|
633
|
+
if ( hash_table_is_empty( tx->waiting_dpid ) ) {
|
634
|
+
// was last element in tx. callback result.
|
635
|
+
if ( all_param->callback != NULL ) {
|
636
|
+
all_param->callback( tx->tx_result, all_param->user_data );
|
637
|
+
}
|
638
|
+
|
639
|
+
info( "txid %#x complete.", tx->txid );
|
640
|
+
// remove and cleanup tx
|
641
|
+
delete_hash_entry( efi_tx_table, &tx->txid );
|
642
|
+
xfree_all_sw_tx( tx );
|
643
|
+
return;
|
644
|
+
}
|
645
|
+
}
|
646
|
+
|
647
|
+
|
648
|
+
all_sw_tx*
|
649
|
+
_insert_tx( size_t n_dpids, struct event_forward_operation_to_all_request_param *param ) {
|
650
|
+
all_sw_tx *tx = xcalloc( 1, sizeof(all_sw_tx) );
|
651
|
+
tx->txid = get_txid();
|
652
|
+
info( "txid %#x Start dispatching to switches", tx->txid );
|
653
|
+
tx->request_param = param;
|
654
|
+
tx->tx_result = EFI_OPERATION_SUCCEEDED;
|
655
|
+
tx->waiting_dpid = create_hash_with_size( compare_datapath_id,
|
656
|
+
hash_datapath_id,
|
657
|
+
( unsigned ) n_dpids );
|
658
|
+
void *dupe_tx = insert_hash_entry( efi_tx_table, &tx->txid, tx );
|
659
|
+
assert( dupe_tx == NULL );
|
660
|
+
return tx;
|
661
|
+
}
|
662
|
+
|
663
|
+
|
664
|
+
void
|
665
|
+
_dispatch_to_all_switch( uint64_t *dpids, size_t n_dpids, void *user_data ) {
|
666
|
+
struct event_forward_operation_to_all_request_param *param = user_data;
|
667
|
+
|
668
|
+
all_sw_tx *tx = _insert_tx( n_dpids, param );
|
669
|
+
|
670
|
+
// copy dpid hash to transaction.
|
671
|
+
for ( size_t i = 0 ; i < n_dpids ; ++i ) {
|
672
|
+
uint64_t *dpid = xmalloc( sizeof( uint64_t ) );
|
673
|
+
*dpid = dpids[i];
|
674
|
+
uint64_t *dupe_dpid = insert_hash_entry( tx->waiting_dpid, dpid, dpid );
|
675
|
+
if ( dupe_dpid == NULL ) {
|
676
|
+
struct txinfo *txinfo = xcalloc( 1, sizeof( struct txinfo ) );
|
677
|
+
txinfo->dpid = *dpid;
|
678
|
+
txinfo->txid = tx->txid;
|
679
|
+
bool send_ok;
|
680
|
+
|
681
|
+
if ( param->add ) {
|
682
|
+
send_ok = add_switch_event_forward_entry( *dpid, param->type, param->service_name, _switch_response_handler, txinfo );
|
683
|
+
}
|
684
|
+
else {
|
685
|
+
send_ok = delete_switch_event_forward_entry( *dpid, param->type, param->service_name, _switch_response_handler, txinfo );
|
686
|
+
}
|
687
|
+
|
688
|
+
if ( !send_ok ) {
|
689
|
+
tx->tx_result = EFI_OPERATION_FAILED;
|
690
|
+
warn( "txid %#x Failed to send request to switch %#" PRIx64 ".", tx->txid, *dpid );
|
691
|
+
xfree( delete_hash_entry( tx->waiting_dpid, dpid ) );
|
692
|
+
dpid = NULL;
|
693
|
+
xfree( txinfo );
|
694
|
+
continue;
|
695
|
+
}
|
696
|
+
|
697
|
+
struct itimerspec interval;
|
698
|
+
interval.it_interval.tv_sec = 0;
|
699
|
+
interval.it_interval.tv_nsec = 0;
|
700
|
+
interval.it_value.tv_sec = 5; // FIXME make this configurable?
|
701
|
+
interval.it_value.tv_nsec = 0;
|
702
|
+
bool set_ok = add_timer_event_callback( &interval, _switch_response_timeout, txinfo );
|
703
|
+
if ( !set_ok ) {
|
704
|
+
tx->tx_result = EFI_OPERATION_FAILED;
|
705
|
+
warn( "txid %#x Failed to set timeout timer for switch %#" PRIx64 ".", tx->txid, *dpid );
|
706
|
+
xfree( delete_hash_entry( tx->waiting_dpid, dpid ) );
|
707
|
+
dpid = NULL;
|
708
|
+
// txinfo will be freed by _switch_response_handler
|
709
|
+
continue;
|
710
|
+
}
|
711
|
+
}
|
712
|
+
else {
|
713
|
+
warn( "Duplicate dpid returned %#." PRIx64, *dupe_dpid );
|
714
|
+
xfree( dupe_dpid );
|
715
|
+
}
|
716
|
+
}
|
717
|
+
|
718
|
+
if ( tx->tx_result == EFI_OPERATION_FAILED ) {
|
719
|
+
if ( param->callback != NULL ) {
|
720
|
+
param->callback( tx->tx_result, param->user_data );
|
721
|
+
}
|
722
|
+
info( "txid %#x completed with failure.", tx->txid );
|
723
|
+
// remove and cleanup tx
|
724
|
+
delete_hash_entry( efi_tx_table, &tx->txid );
|
725
|
+
xfree_all_sw_tx( tx );
|
726
|
+
}
|
727
|
+
}
|
728
|
+
|
729
|
+
|
730
|
+
void
|
731
|
+
_get_switch_list_after_swm_succ( event_forward_operation_result result, void *user_data ) {
|
732
|
+
struct event_forward_operation_to_all_request_param *param = user_data;
|
733
|
+
bool success = true;
|
734
|
+
if ( result.result == EFI_OPERATION_SUCCEEDED ) {
|
735
|
+
// get switch list
|
736
|
+
success = send_efi_switch_list_request( _dispatch_to_all_switch, param );
|
737
|
+
}
|
738
|
+
else {
|
739
|
+
success = false;
|
740
|
+
}
|
741
|
+
|
742
|
+
if ( !success ) {
|
743
|
+
warn( "Failed to set event forwarding entry to switch manager." );
|
744
|
+
if ( param->callback != NULL ) {
|
745
|
+
param->callback( EFI_OPERATION_FAILED, param->user_data );
|
746
|
+
}
|
747
|
+
xfree_event_forward_operation_to_all_request_param( param );
|
748
|
+
}
|
749
|
+
}
|
750
|
+
|
751
|
+
|
752
|
+
bool
|
753
|
+
add_event_forward_entry_to_all_switches( enum efi_event_type type, const char *service_name, event_forward_entry_to_all_callback callback, void *user_data ) {
|
754
|
+
struct event_forward_operation_to_all_request_param *param = xcalloc( 1, sizeof( struct event_forward_operation_to_all_request_param ) );
|
755
|
+
param->add = true;
|
756
|
+
param->type = type;
|
757
|
+
param->service_name = xstrdup( service_name );
|
758
|
+
param->callback = callback;
|
759
|
+
param->user_data = user_data;
|
760
|
+
bool sent_ok = add_switch_manager_event_forward_entry( type, service_name, _get_switch_list_after_swm_succ, param );
|
761
|
+
if ( !sent_ok ) {
|
762
|
+
xfree_event_forward_operation_to_all_request_param( param );
|
763
|
+
}
|
764
|
+
return sent_ok;
|
765
|
+
}
|
766
|
+
|
767
|
+
|
768
|
+
bool
|
769
|
+
delete_event_forward_entry_to_all_switches( enum efi_event_type type, const char *service_name, event_forward_entry_to_all_callback callback, void *user_data ) {
|
770
|
+
struct event_forward_operation_to_all_request_param *param = xcalloc( 1, sizeof( struct event_forward_operation_to_all_request_param ) );
|
771
|
+
param->add = false;
|
772
|
+
param->type = type;
|
773
|
+
param->service_name = xstrdup( service_name );
|
774
|
+
param->callback = callback;
|
775
|
+
param->user_data = user_data;
|
776
|
+
bool sent_ok = delete_switch_manager_event_forward_entry( type, service_name, _get_switch_list_after_swm_succ, param );
|
777
|
+
if ( !sent_ok ) {
|
778
|
+
xfree_event_forward_operation_to_all_request_param( param );
|
779
|
+
}
|
780
|
+
return sent_ok;
|
781
|
+
}
|
782
|
+
|
783
|
+
|