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
data/src/lib/packet_parser.c
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Author: Kazuya Suzuki
|
|
3
|
-
*
|
|
4
2
|
* Copyright (C) 2008-2012 NEC Corporation
|
|
5
3
|
*
|
|
6
4
|
* This program is free software; you can redistribute it and/or modify
|
|
@@ -20,6 +18,7 @@
|
|
|
20
18
|
|
|
21
19
|
#include <assert.h>
|
|
22
20
|
#include <stdint.h>
|
|
21
|
+
#include <arpa/inet.h>
|
|
23
22
|
#include <net/ethernet.h>
|
|
24
23
|
#include <netinet/ip.h>
|
|
25
24
|
#include "packet_info.h"
|
|
@@ -202,6 +201,38 @@ parse_ipv4( buffer *buf ) {
|
|
|
202
201
|
}
|
|
203
202
|
|
|
204
203
|
|
|
204
|
+
static void
|
|
205
|
+
parse_ipv6( buffer *buf ) {
|
|
206
|
+
assert( buf != NULL );
|
|
207
|
+
|
|
208
|
+
packet_info *packet_info = buf->user_data;
|
|
209
|
+
void *ptr = packet_info->l3_header;
|
|
210
|
+
assert( ptr != NULL );
|
|
211
|
+
|
|
212
|
+
// Check the length of remained buffer for an ipv6 header without nexthdr.
|
|
213
|
+
size_t length = REMAINED_BUFFER_LENGTH( buf, ptr );
|
|
214
|
+
if ( length < sizeof( ipv6_header_t ) ) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Parses IPv6 header
|
|
219
|
+
ipv6_header_t *ipv6_header = ptr;
|
|
220
|
+
uint32_t hdrctl = ntohl( ipv6_header->hdrctl );
|
|
221
|
+
packet_info->ipv6_version = ( uint8_t )( hdrctl >> 28 );
|
|
222
|
+
packet_info->ipv6_tc = ( uint8_t )( hdrctl >> 20 & 0xFF );
|
|
223
|
+
packet_info->ipv6_flowlabel = hdrctl & 0xFFFFF;
|
|
224
|
+
packet_info->ipv6_plen = ntohs( ipv6_header->plen );
|
|
225
|
+
packet_info->ipv6_nexthdr = ipv6_header->nexthdr;
|
|
226
|
+
packet_info->ipv6_hoplimit = ipv6_header->hoplimit;
|
|
227
|
+
memcpy( packet_info->ipv6_saddr, ipv6_header->saddr, IPV6_ADDRLEN );
|
|
228
|
+
memcpy( packet_info->ipv6_daddr, ipv6_header->daddr, IPV6_ADDRLEN );
|
|
229
|
+
|
|
230
|
+
packet_info->format |= NW_IPV6;
|
|
231
|
+
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
205
236
|
static void
|
|
206
237
|
parse_lldp( buffer *buf ) {
|
|
207
238
|
assert( buf != NULL );
|
|
@@ -439,6 +470,11 @@ parse_packet( buffer *buf ) {
|
|
|
439
470
|
parse_ipv4( buf );
|
|
440
471
|
break;
|
|
441
472
|
|
|
473
|
+
case ETH_ETHTYPE_IPV6:
|
|
474
|
+
packet_info->l3_header = packet_info->l2_payload;
|
|
475
|
+
parse_ipv6( buf );
|
|
476
|
+
break;
|
|
477
|
+
|
|
442
478
|
case ETH_ETHTYPE_LLDP:
|
|
443
479
|
packet_info->l3_header = packet_info->l2_payload;
|
|
444
480
|
parse_lldp( buf );
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Author: Kazushi SUGYO, 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 <arpa/inet.h>
|
|
22
|
+
#include <assert.h>
|
|
23
|
+
#include <errno.h>
|
|
24
|
+
#include <fcntl.h>
|
|
25
|
+
#include <netinet/in.h>
|
|
26
|
+
#include <netinet/tcp.h>
|
|
27
|
+
#include <stdio.h>
|
|
28
|
+
#include <stdlib.h>
|
|
29
|
+
#include <string.h>
|
|
30
|
+
#include <sys/socket.h>
|
|
31
|
+
#include <sys/types.h>
|
|
32
|
+
#include <unistd.h>
|
|
33
|
+
#include "buffer.h"
|
|
34
|
+
#include "checks.h"
|
|
35
|
+
#include "event_handler.h"
|
|
36
|
+
#include "log.h"
|
|
37
|
+
#include "message_queue.h"
|
|
38
|
+
#include "openflow.h"
|
|
39
|
+
#include "openflow_switch_interface.h"
|
|
40
|
+
#include "secure_channel.h"
|
|
41
|
+
#include "timer.h"
|
|
42
|
+
#include "wrapper.h"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
enum connection_state {
|
|
46
|
+
INIT,
|
|
47
|
+
CONNECTING,
|
|
48
|
+
CONNECTED,
|
|
49
|
+
DISCONNECTED,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
static char connection_state_string[][ 13 ] = { "INIT", "CONNECTING", "CONNECTED", "DISCONNECTED" };
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
typedef struct {
|
|
56
|
+
uint32_t ip;
|
|
57
|
+
uint16_t port;
|
|
58
|
+
int fd;
|
|
59
|
+
int state;
|
|
60
|
+
connected_handler connected_callback;
|
|
61
|
+
disconnected_handler disconnected_callback;
|
|
62
|
+
} secure_channel_connection;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
static secure_channel_connection connection = { 0, 0, -1, INIT, NULL, NULL };
|
|
66
|
+
static bool secure_channel_initialized = false;
|
|
67
|
+
|
|
68
|
+
static message_queue *send_queue = NULL;
|
|
69
|
+
static message_queue *recv_queue = NULL;
|
|
70
|
+
|
|
71
|
+
static const size_t RECEIVE_BUFFFER_SIZE = UINT16_MAX + sizeof( struct ofp_packet_in ) - 2;
|
|
72
|
+
static buffer *fragment_buf = NULL;
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
static void
|
|
76
|
+
transit_state( int state ) {
|
|
77
|
+
switch ( connection.state ) {
|
|
78
|
+
case INIT:
|
|
79
|
+
{
|
|
80
|
+
if ( state != CONNECTING ) {
|
|
81
|
+
goto invalid_transition;
|
|
82
|
+
}
|
|
83
|
+
connection.state = state;
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case CONNECTING:
|
|
88
|
+
{
|
|
89
|
+
if ( state != CONNECTED && state != CONNECTING ) {
|
|
90
|
+
goto invalid_transition;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
|
|
95
|
+
case CONNECTED:
|
|
96
|
+
{
|
|
97
|
+
if ( state != DISCONNECTED && state != INIT ) {
|
|
98
|
+
goto invalid_transition;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
|
|
103
|
+
case DISCONNECTED:
|
|
104
|
+
{
|
|
105
|
+
if ( state != CONNECTED ) {
|
|
106
|
+
goto invalid_transition;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
default:
|
|
112
|
+
{
|
|
113
|
+
error( "Invalid state ( %d ).", connection.state );
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
debug( "State transition: %s -> %s.",
|
|
120
|
+
connection_state_string[ connection.state ],
|
|
121
|
+
connection_state_string[ state ] );
|
|
122
|
+
|
|
123
|
+
connection.state = state;
|
|
124
|
+
|
|
125
|
+
return;
|
|
126
|
+
|
|
127
|
+
invalid_transition:
|
|
128
|
+
error( "Invalid state transition ( %d -> %d ).", connection.state, state );
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
static void
|
|
133
|
+
clear_connection() {
|
|
134
|
+
if ( connection.fd >= 0 ) {
|
|
135
|
+
close( connection.fd );
|
|
136
|
+
set_readable( connection.fd, false );
|
|
137
|
+
set_writable( connection.fd, false );
|
|
138
|
+
delete_fd_handler( connection.fd );
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
connection.fd = -1;
|
|
142
|
+
connection.state = INIT;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
static void reconnect( void *user_data );
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
static void
|
|
150
|
+
disconnected() {
|
|
151
|
+
transit_state( DISCONNECTED );
|
|
152
|
+
|
|
153
|
+
if ( connection.disconnected_callback != NULL ) {
|
|
154
|
+
connection.disconnected_callback();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
clear_connection();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
static bool
|
|
162
|
+
recv_message_from_secure_channel() {
|
|
163
|
+
assert( recv_queue != NULL );
|
|
164
|
+
|
|
165
|
+
if ( recv_queue->length == 0 ) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
buffer *message = dequeue_message( recv_queue );
|
|
170
|
+
handle_secure_channel_message( message ); // FIXME: handle error properly
|
|
171
|
+
free_buffer( message );
|
|
172
|
+
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
static void
|
|
178
|
+
recv_from_secure_channel( int fd, void *user_data ) {
|
|
179
|
+
UNUSED( fd );
|
|
180
|
+
UNUSED( user_data );
|
|
181
|
+
|
|
182
|
+
// all queued messages should be processed before receiving new messages from remote
|
|
183
|
+
if ( recv_queue->length > 0 ) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if ( fragment_buf == NULL ) {
|
|
188
|
+
fragment_buf = alloc_buffer_with_length( RECEIVE_BUFFFER_SIZE );
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
size_t remaining_length = RECEIVE_BUFFFER_SIZE - fragment_buf->length;
|
|
192
|
+
char *recv_buf = ( char * ) fragment_buf->data + fragment_buf->length;
|
|
193
|
+
ssize_t recv_length = read( connection.fd, recv_buf, remaining_length );
|
|
194
|
+
if ( recv_length < 0 ) {
|
|
195
|
+
if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
error( "Receive error ( errno = %s [%d] ).", strerror( errno ), errno );
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if ( recv_length == 0 ) {
|
|
202
|
+
debug( "Connection closed by peer." );
|
|
203
|
+
disconnected();
|
|
204
|
+
reconnect( NULL );
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
fragment_buf->length += ( size_t ) recv_length;
|
|
208
|
+
|
|
209
|
+
size_t read_total = 0;
|
|
210
|
+
while ( fragment_buf->length >= sizeof( struct ofp_header ) ) {
|
|
211
|
+
struct ofp_header *header = fragment_buf->data;
|
|
212
|
+
uint16_t message_length = ntohs( header->length );
|
|
213
|
+
if ( message_length > fragment_buf->length ) {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
buffer *message = alloc_buffer_with_length( message_length );
|
|
217
|
+
char *p = append_back_buffer( message, message_length );
|
|
218
|
+
memcpy( p, fragment_buf->data, message_length );
|
|
219
|
+
remove_front_buffer( fragment_buf, message_length );
|
|
220
|
+
enqueue_message( recv_queue, message );
|
|
221
|
+
read_total += message_length;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// remove headroom manually for next call
|
|
225
|
+
if ( read_total > 0 ) {
|
|
226
|
+
memmove( ( char * ) fragment_buf->data - read_total, fragment_buf->data, fragment_buf->length );
|
|
227
|
+
fragment_buf->data = ( char * ) fragment_buf->data - read_total;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
while ( recv_message_from_secure_channel() == true );
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
static void
|
|
235
|
+
flush_send_queue( int fd, void *user_data ) {
|
|
236
|
+
UNUSED( fd );
|
|
237
|
+
UNUSED( user_data );
|
|
238
|
+
|
|
239
|
+
assert( send_queue != NULL );
|
|
240
|
+
assert( connection.fd >= 0 );
|
|
241
|
+
|
|
242
|
+
debug( "Flushing send queue ( length = %d ).", send_queue->length );
|
|
243
|
+
|
|
244
|
+
set_writable( connection.fd, false );
|
|
245
|
+
|
|
246
|
+
buffer *buf = NULL;
|
|
247
|
+
while ( ( buf = peek_message( send_queue ) ) != NULL ) {
|
|
248
|
+
ssize_t write_length = write( connection.fd, buf->data, buf->length );
|
|
249
|
+
if ( write_length < 0 ) {
|
|
250
|
+
if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) {
|
|
251
|
+
set_writable( connection.fd, true );
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
error( "Failed to send a message to secure channel ( errno = %s [%d] ).",
|
|
255
|
+
strerror( errno ), errno );
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
if ( ( size_t ) write_length < buf->length ) {
|
|
259
|
+
remove_front_buffer( buf, ( size_t ) write_length );
|
|
260
|
+
set_writable( connection.fd, true );
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
buf = dequeue_message( send_queue );
|
|
265
|
+
free_buffer( buf );
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
static void
|
|
271
|
+
connected() {
|
|
272
|
+
transit_state( CONNECTED );
|
|
273
|
+
|
|
274
|
+
set_fd_handler( connection.fd, recv_from_secure_channel, NULL, flush_send_queue, NULL );
|
|
275
|
+
set_readable( connection.fd, true );
|
|
276
|
+
set_writable( connection.fd, false );
|
|
277
|
+
|
|
278
|
+
if ( connection.connected_callback != NULL ) {
|
|
279
|
+
connection.connected_callback();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
static bool try_connect( void );
|
|
285
|
+
|
|
286
|
+
static void
|
|
287
|
+
reconnect( void *user_data ) {
|
|
288
|
+
UNUSED( user_data );
|
|
289
|
+
bool ret = try_connect();
|
|
290
|
+
if ( ret == false ) {
|
|
291
|
+
error( "Failed to reconnect." );
|
|
292
|
+
clear_connection();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
static void
|
|
298
|
+
backoff() {
|
|
299
|
+
if ( connection.fd >= 0 ) {
|
|
300
|
+
close( connection.fd );
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
struct itimerspec spec = { { 0, 0 }, { 5, 0 } };
|
|
304
|
+
add_timer_event_callback( &spec, reconnect, NULL );
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
static void
|
|
309
|
+
check_connected( void *user_data ) {
|
|
310
|
+
UNUSED( user_data );
|
|
311
|
+
|
|
312
|
+
debug( "Checking a connection ( fd = %d ip = %#x, port = %u ).", connection.fd, connection.ip, connection.port );
|
|
313
|
+
|
|
314
|
+
assert( secure_channel_initialized );
|
|
315
|
+
assert( connection.fd >= 0 );
|
|
316
|
+
|
|
317
|
+
set_writable( connection.fd, false );
|
|
318
|
+
delete_fd_handler( connection.fd );
|
|
319
|
+
|
|
320
|
+
int err = 0;
|
|
321
|
+
socklen_t length = sizeof( error );
|
|
322
|
+
int ret = getsockopt( connection.fd, SOL_SOCKET, SO_ERROR, &err, &length );
|
|
323
|
+
if ( ret < 0 ) {
|
|
324
|
+
error( "Failed to retrieve error code ( fd = %d, ret = %d, errno = %s [%d] ).",
|
|
325
|
+
connection.fd, ret, strerror( errno ), errno );
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
switch( err ) {
|
|
330
|
+
case 0:
|
|
331
|
+
connected();
|
|
332
|
+
break;
|
|
333
|
+
|
|
334
|
+
case EINTR:
|
|
335
|
+
case EAGAIN:
|
|
336
|
+
case ECONNREFUSED:
|
|
337
|
+
case ENETUNREACH:
|
|
338
|
+
case ETIMEDOUT:
|
|
339
|
+
warn( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err );
|
|
340
|
+
backoff();
|
|
341
|
+
return;
|
|
342
|
+
|
|
343
|
+
case EINPROGRESS:
|
|
344
|
+
set_fd_handler( connection.fd, NULL ,NULL, ( event_fd_callback ) check_connected, NULL );
|
|
345
|
+
set_writable( connection.fd, true );
|
|
346
|
+
break;
|
|
347
|
+
|
|
348
|
+
default:
|
|
349
|
+
error( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err );
|
|
350
|
+
clear_connection();
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
static bool
|
|
357
|
+
try_connect() {
|
|
358
|
+
assert( connection.state != CONNECTED );
|
|
359
|
+
|
|
360
|
+
int fd = socket( PF_INET, SOCK_STREAM, 0 );
|
|
361
|
+
if ( fd < 0 ) {
|
|
362
|
+
error( "Failed to create a socket ( ret = %d, errno = %s [%d] ).",
|
|
363
|
+
fd, strerror( errno ), errno );
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
int flag = 1;
|
|
368
|
+
int ret = setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof( flag ) );
|
|
369
|
+
if ( ret < 0 ) {
|
|
370
|
+
error( "Failed to set socket options ( fd = %d, ret = %d, errno = %s [%d] ).",
|
|
371
|
+
fd, ret, strerror( errno ), errno );
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
ret = fcntl( fd, F_SETFL, O_NONBLOCK );
|
|
376
|
+
if ( ret < 0 ) {
|
|
377
|
+
error( "Failed to enable non-blocking mode ( fd = %d, ret = %d, errno = %s [%d] ).",
|
|
378
|
+
fd, ret, strerror( errno ), errno );
|
|
379
|
+
|
|
380
|
+
close( fd );
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
connection.fd = fd;
|
|
385
|
+
|
|
386
|
+
struct sockaddr_in addr;
|
|
387
|
+
memset( &addr, 0, sizeof( struct sockaddr_in ) );
|
|
388
|
+
addr.sin_family = AF_INET;
|
|
389
|
+
addr.sin_port = htons( connection.port );
|
|
390
|
+
addr.sin_addr.s_addr = htonl( connection.ip );
|
|
391
|
+
|
|
392
|
+
transit_state( CONNECTING );
|
|
393
|
+
|
|
394
|
+
ret = connect( connection.fd, ( struct sockaddr * ) &addr, sizeof( struct sockaddr_in ) );
|
|
395
|
+
if ( ret < 0 ) {
|
|
396
|
+
switch( errno ) {
|
|
397
|
+
case EINTR:
|
|
398
|
+
case EAGAIN:
|
|
399
|
+
case ECONNREFUSED:
|
|
400
|
+
case ENETUNREACH:
|
|
401
|
+
case ETIMEDOUT:
|
|
402
|
+
warn( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).",
|
|
403
|
+
connection.fd, ret, strerror( errno ), errno );
|
|
404
|
+
backoff();
|
|
405
|
+
return true;
|
|
406
|
+
|
|
407
|
+
case EINPROGRESS:
|
|
408
|
+
break;
|
|
409
|
+
|
|
410
|
+
default:
|
|
411
|
+
error( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).",
|
|
412
|
+
connection.fd, ret, strerror( errno ), errno );
|
|
413
|
+
clear_connection();
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
set_fd_handler( connection.fd, NULL, NULL, ( event_fd_callback ) check_connected, NULL );
|
|
419
|
+
set_writable( connection.fd, true );
|
|
420
|
+
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
bool
|
|
426
|
+
init_secure_channel( uint32_t ip, uint16_t port, connected_handler connected_callback, disconnected_handler disconnected_callback ) {
|
|
427
|
+
assert( !secure_channel_initialized );
|
|
428
|
+
|
|
429
|
+
connection.ip = ip;
|
|
430
|
+
connection.port = port;
|
|
431
|
+
connection.fd = -1;
|
|
432
|
+
connection.connected_callback = connected_callback;
|
|
433
|
+
connection.disconnected_callback = disconnected_callback;
|
|
434
|
+
|
|
435
|
+
bool ret = try_connect();
|
|
436
|
+
if ( ret == false ) {
|
|
437
|
+
clear_connection();
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
send_queue = create_message_queue();
|
|
442
|
+
recv_queue = create_message_queue();
|
|
443
|
+
|
|
444
|
+
secure_channel_initialized = true;
|
|
445
|
+
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
bool
|
|
451
|
+
finalize_secure_channel() {
|
|
452
|
+
assert( secure_channel_initialized );
|
|
453
|
+
|
|
454
|
+
clear_connection();
|
|
455
|
+
|
|
456
|
+
if ( send_queue != NULL ) {
|
|
457
|
+
delete_message_queue( send_queue );
|
|
458
|
+
send_queue = NULL;
|
|
459
|
+
}
|
|
460
|
+
if ( recv_queue != NULL ) {
|
|
461
|
+
delete_message_queue( recv_queue );
|
|
462
|
+
recv_queue = NULL;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
secure_channel_initialized = false;
|
|
466
|
+
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
bool
|
|
472
|
+
send_message_to_secure_channel( buffer *message ) {
|
|
473
|
+
assert( send_queue != NULL );
|
|
474
|
+
assert( message != NULL );
|
|
475
|
+
assert( message->length > 0 );
|
|
476
|
+
assert( connection.state == CONNECTED );
|
|
477
|
+
assert( connection.fd >= 0 );
|
|
478
|
+
|
|
479
|
+
debug( "Enqueuing a message to send queue ( queue length = %d, message length = %d ).",
|
|
480
|
+
send_queue->length, message->length );
|
|
481
|
+
|
|
482
|
+
if ( send_queue->length == 0 ) {
|
|
483
|
+
set_writable( connection.fd, true );
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
buffer *duplicated = duplicate_buffer( message );
|
|
487
|
+
enqueue_message( send_queue, duplicated );
|
|
488
|
+
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
/*
|
|
494
|
+
* Local variables:
|
|
495
|
+
* c-basic-offset: 2
|
|
496
|
+
* indent-tabs-mode: nil
|
|
497
|
+
* End:
|
|
498
|
+
*/
|