/* * Unit tests for OpenFlow Application Interface. * * Copyright (C) 2008-2013 NEC Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "bool.h" #include "checks.h" #include "cmockery_trema.h" #include "hash_table.h" #include "linked_list.h" #include "log.h" #include "messenger.h" #include "openflow_application_interface.h" #include "openflow_message.h" #include "stat.h" #include "wrapper.h" /******************************************************************************** * Helpers. ********************************************************************************/ extern bool openflow_application_interface_initialized; extern openflow_event_handlers_t event_handlers; extern char service_name[ MESSENGER_SERVICE_NAME_LENGTH ]; extern hash_table *stats; extern void assert_if_not_initialized(); extern void handle_error( const uint64_t datapath_id, buffer *data ); extern void handle_echo_reply( const uint64_t datapath_id, buffer *data ); extern void handle_vendor( const uint64_t datapath_id, buffer *data ); extern void handle_features_reply( const uint64_t datapath_id, buffer *data ); extern void handle_get_config_reply( const uint64_t datapath_id, buffer *data ); extern void handle_packet_in( const uint64_t datapath_id, buffer *data ); extern void handle_flow_removed( const uint64_t datapath_id, buffer *data ); extern void handle_port_status( const uint64_t datapath_id, buffer *data ); extern void handle_stats_reply( const uint64_t datapath_id, buffer *data ); extern void handle_barrier_reply( const uint64_t datapath_id, buffer *data ); extern void handle_queue_get_config_reply( const uint64_t datapath_id, buffer *data ); extern void dump_buf( const buffer *data ); extern void handle_switch_events( uint16_t type, void *data, size_t length ); extern void handle_openflow_message( void *data, size_t length ); extern void handle_message( uint16_t type, void *data, size_t length ); extern void insert_dpid( list_element **head, uint64_t *dpid ); extern void handle_list_switches_reply( uint16_t message_type, void *data, size_t length, void *user_data ); #define SWITCH_READY_HANDLER ( ( void * ) 0x00020001 ) #define SWITCH_READY_USER_DATA ( ( void * ) 0x00020011 ) #define SWITCH_DISCONNECTED_HANDLER ( ( void * ) 0x00020002 ) #define SWITCH_DISCONNECTED_USER_DATA ( ( void * ) 0x00020021 ) #define ERROR_HANDLER ( ( void * ) 0x00010001 ) #define ERROR_USER_DATA ( ( void * ) 0x00010011 ) #define ECHO_REPLY_HANDLER ( ( void * ) 0x00010002 ) #define ECHO_REPLY_USER_DATA ( ( void * ) 0x00010021 ) #define VENDOR_HANDLER ( ( void * ) 0x00010003 ) #define VENDOR_USER_DATA ( ( void * ) 0x00010031 ) #define FEATURES_REPLY_HANDLER ( ( void * ) 0x00010004 ) #define FEATURES_REPLY_USER_DATA ( ( void * ) 0x00010041 ) #define GET_CONFIG_REPLY_HANDLER ( ( void * ) 0x00010005 ) #define GET_CONFIG_REPLY_USER_DATA ( ( void * ) 0x00010051 ) #define PACKET_IN_HANDLER ( ( void * ) 0x00010006 ) #define PACKET_IN_USER_DATA ( ( void * ) 0x00010061 ) #define FLOW_REMOVED_HANDLER ( ( void * ) 0x00010007 ) #define FLOW_REMOVED_USER_DATA ( ( void * ) 0x00010071 ) #define PORT_STATUS_HANDLER ( ( void * ) 0x00010008 ) #define PORT_STATUS_USER_DATA ( ( void * ) 0x00010081 ) #define STATS_REPLY_HANDLER ( ( void * ) 0x00010009 ) #define STATS_REPLY_USER_DATA ( ( void * ) 0x00010091 ) #define BARRIER_REPLY_HANDLER ( ( void * ) 0x0001000a ) #define BARRIER_REPLY_USER_DATA ( ( void * ) 0x000100a1 ) #define QUEUE_GET_CONFIG_REPLY_HANDLER ( ( void * ) 0x0001000b ) #define QUEUE_GET_CONFIG_REPLY_USER_DATA ( ( void * ) 0x000100b1 ) #define LIST_SWITCHES_REPLY_HANDLER ( ( void * ) 0x0001000c ) #define LIST_SWITCHES_REPLY_USER_DATA ( ( void * ) 0x000100c1 ) static const pid_t PID = 12345; static char SERVICE_NAME[] = "learning switch application 0"; static openflow_event_handlers_t NULL_EVENT_HANDLERS = { false, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, false, ( void * ) 0, ( void * ) 0, false, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0, ( void * ) 0 }; static openflow_event_handlers_t EVENT_HANDLERS = { false, SWITCH_READY_HANDLER, SWITCH_READY_USER_DATA, SWITCH_DISCONNECTED_HANDLER, SWITCH_DISCONNECTED_USER_DATA, ERROR_HANDLER, ERROR_USER_DATA, ECHO_REPLY_HANDLER, ECHO_REPLY_USER_DATA, VENDOR_HANDLER, VENDOR_USER_DATA, FEATURES_REPLY_HANDLER, FEATURES_REPLY_USER_DATA, GET_CONFIG_REPLY_HANDLER, GET_CONFIG_REPLY_USER_DATA, false, PACKET_IN_HANDLER, PACKET_IN_USER_DATA, false, FLOW_REMOVED_HANDLER, FLOW_REMOVED_USER_DATA, PORT_STATUS_HANDLER, PORT_STATUS_USER_DATA, STATS_REPLY_HANDLER, STATS_REPLY_USER_DATA, BARRIER_REPLY_HANDLER, BARRIER_REPLY_USER_DATA, QUEUE_GET_CONFIG_REPLY_HANDLER, QUEUE_GET_CONFIG_REPLY_USER_DATA, LIST_SWITCHES_REPLY_HANDLER }; static uint64_t DATAPATH_ID = 0x0102030405060708ULL; static char REMOTE_SERVICE_NAME[] = "switch.0x102030405060708"; static const uint32_t TRANSACTION_ID = 0x04030201; static const uint32_t VENDOR_ID = 0xccddeeff; static const uint8_t MAC_ADDR_X[ OFP_ETH_ALEN ] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 }; static const uint8_t MAC_ADDR_Y[ OFP_ETH_ALEN ] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d }; static const char *PORT_NAME = "port 1"; static const uint32_t PORT_FEATURES = ( OFPPF_10MB_HD | OFPPF_10MB_FD | OFPPF_100MB_HD | OFPPF_100MB_FD | OFPPF_1GB_HD | OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_AUTONEG | OFPPF_PAUSE ); static struct ofp_match MATCH = { OFPFW_ALL, 1, { 0x01, 0x02, 0x03, 0x04, 0x05, 0x07 }, { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d }, 1, 1, { 0 }, 0x800, 0xfc, 0x6, { 0, 0 }, 0x0a090807, 0x0a090807, 1024, 2048 }; #define USER_DATA_LEN 64 static uint8_t USER_DATA[ USER_DATA_LEN ]; static bool packet_in_handler_called = false; /******************************************************************************** * Mocks. ********************************************************************************/ const char * mock_get_trema_name() { return "TEST_SERVICE_NAME"; } pid_t mock_getpid() { return PID; } bool mock_init_openflow_message() { return ( bool ) mock(); } bool mock_add_message_received_callback( char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len ) ) { check_expected( service_name ); check_expected( callback ); return ( bool ) mock(); } bool mock_add_message_replied_callback( char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) { check_expected( service_name ); check_expected( callback ); return ( bool ) mock(); } bool mock_send_message( char *service_name, uint16_t tag, void *data, size_t len ) { uint32_t tag32 = tag; check_expected( service_name ); check_expected( tag32 ); check_expected( data ); check_expected( len ); return ( bool ) mock(); } bool mock_send_request_message( char *to_service_name, char *from_service_name, uint16_t tag, void *data, size_t len, void *user_data ) { uint32_t tag32 = tag; check_expected( to_service_name ); check_expected( from_service_name ); check_expected( tag32 ); check_expected( data ); check_expected( len ); check_expected( user_data ); return ( bool ) mock(); } bool mock_delete_message_received_callback( char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len ) ) { check_expected( service_name ); check_expected( callback ); return ( bool ) mock(); } bool mock_delete_message_replied_callback( char *service_name, void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) { check_expected( service_name ); check_expected( callback ); return ( bool ) mock(); } bool mock_clear_send_queue( const char *service_name ) { check_expected( service_name ); return ( bool ) mock(); } bool mock_parse_packet( buffer *buf ) { calloc_packet_info( buf ); return ( bool ) mock(); } static void mock_switch_disconnected_handler( uint64_t datapath_id, void *user_data ) { check_expected( &datapath_id ); check_expected( user_data ); } static void mock_error_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t code, const buffer *data, void *user_data ) { uint32_t type32 = type; uint32_t code32 = code; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( type32 ); check_expected( code32 ); check_expected( data->length ); check_expected( data->data ); check_expected( user_data ); } static void mock_echo_reply_handler( uint64_t datapath_id, uint32_t transaction_id, const buffer *data, void *user_data ) { void *data_uc; check_expected( &datapath_id ); check_expected( transaction_id ); if ( data != NULL ) { check_expected( data->length ); check_expected( data->data ); } else { data_uc = ( void * ) ( unsigned long ) data; check_expected( data_uc ); } check_expected( user_data ); } static void mock_vendor_handler( uint64_t datapath_id, uint32_t transaction_id, uint32_t vendor, const buffer *data, void *user_data ) { void *data_uc; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( vendor ); if ( data != NULL ) { check_expected( data->length ); check_expected( data->data ); } else { data_uc = ( void * ) ( unsigned long ) data; check_expected( data_uc ); } check_expected( user_data ); } static void mock_features_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint32_t n_buffers, uint8_t n_tables, uint32_t capabilities, uint32_t actions, const list_element *phy_ports, void *user_data ) { uint32_t n_tables32 = n_tables; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( n_buffers ); check_expected( n_tables32 ); check_expected( capabilities ); check_expected( actions ); if ( phy_ports != NULL ) { struct ofp_phy_port *port1 = phy_ports->data; struct ofp_phy_port *port2 = phy_ports->next->data; check_expected( port1 ); check_expected( port2 ); } else { void *phy_ports_uc = ( void * ) ( unsigned long ) phy_ports; check_expected( phy_ports_uc ); } check_expected( user_data ); } static void mock_get_config_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t flags, uint16_t miss_send_len, void *user_data ) { uint32_t flags32 = flags; uint32_t miss_send_len32 = miss_send_len; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( flags32 ); check_expected( miss_send_len32 ); check_expected( user_data ); } static void mock_flow_removed_handler( uint64_t datapath_id, uint32_t transaction_id, struct ofp_match match, uint64_t cookie, uint16_t priority, uint8_t reason, uint32_t duration_sec, uint32_t duration_nsec, uint16_t idle_timeout, uint64_t packet_count, uint64_t byte_count, void *user_data ) { uint32_t priority32 = priority; uint32_t reason32 = reason; uint32_t idle_timeout32 = idle_timeout; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( &match ); check_expected( &cookie ); check_expected( priority32 ); check_expected( reason32 ); check_expected( duration_sec ); check_expected( duration_nsec ); check_expected( idle_timeout32 ); check_expected( &packet_count ); check_expected( &byte_count ); check_expected( user_data ); } static void mock_port_status_handler( uint64_t datapath_id, uint32_t transaction_id, uint8_t reason, struct ofp_phy_port phy_port, void *user_data ) { uint32_t reason32 = reason; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( reason32 ); check_expected( &phy_port ); check_expected( user_data ); } static void mock_stats_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t flags, const buffer *data, void *user_data ) { uint32_t type32 = type; uint32_t flags32 = flags; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( type32 ); check_expected( flags32 ); check_expected( data->length ); check_expected( data->data ); check_expected( user_data ); } static void mock_barrier_reply_handler( uint64_t datapath_id, uint32_t transaction_id, void *user_data ) { check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( user_data ); } static void mock_queue_get_config_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t port, const list_element *queues, void *user_data ) { uint32_t port32 = port; struct ofp_packet_queue *queue1, *queue2; queue1 = queues->data; queue2 = queues->next->data; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( port32 ); check_expected( queue1 ); check_expected( queue2 ); check_expected( user_data ); } static void mock_handle_list_switches_reply( const list_element *switches, void *user_data ) { uint64_t *dpid1, *dpid2, *dpid3; if ( switches != NULL ) { dpid1 = switches->data; check_expected( *dpid1 ); if ( switches->next != NULL ) { dpid2 = switches->next->data; check_expected( *dpid2 ); if ( switches->next->next != NULL ) { dpid3 = switches->next->next->data; check_expected( *dpid3 ); } } } check_expected( user_data ); } void mock_die( char *format, ... ) { check_expected( format ); mock_assert( false, "die", __FILE__, __LINE__ ); } void mock_debug( char *format, ... ) { UNUSED( format ); } void mock_info( char *format, ... ) { UNUSED( format ); } void mock_warn( char *format, ... ) { UNUSED( format ); } void mock_error( char *format, ... ) { UNUSED( format ); } void mock_critical( char *format, ... ) { UNUSED( format ); } static int mock_get_logging_level() { return LOG_DEBUG; } /******************************************************************************** * Setup and teardown function. ********************************************************************************/ static void cleanup() { openflow_application_interface_initialized = false; packet_in_handler_called = false; memset( service_name, 0, sizeof( service_name ) ); memset( &event_handlers, 0, sizeof( event_handlers ) ); memset( USER_DATA, 'Z', sizeof( USER_DATA ) ); if ( stats != NULL ) { delete_hash( stats ); stats = NULL; } } static void init() { bool ret; get_logging_level = mock_get_logging_level; cleanup(); will_return( mock_init_openflow_message, true ); expect_string( mock_add_message_received_callback, service_name, SERVICE_NAME ); expect_value( mock_add_message_received_callback, callback, handle_message ); will_return( mock_add_message_received_callback, true ); expect_string( mock_add_message_replied_callback, service_name, SERVICE_NAME ); expect_value( mock_add_message_replied_callback, callback, handle_list_switches_reply ); will_return( mock_add_message_replied_callback, true ); init_stat(); ret = init_openflow_application_interface( SERVICE_NAME ); assert_true( ret ); assert_true( openflow_application_interface_initialized ); assert_string_equal( service_name, SERVICE_NAME ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * init_openflow_application_interface() tests. ********************************************************************************/ static void test_init_openflow_application_interface_with_valid_custom_service_name() { bool ret; will_return( mock_init_openflow_message, true ); expect_string( mock_add_message_received_callback, service_name, SERVICE_NAME ); expect_value( mock_add_message_received_callback, callback, handle_message ); will_return( mock_add_message_received_callback, true ); expect_string( mock_add_message_replied_callback, service_name, SERVICE_NAME ); expect_value( mock_add_message_replied_callback, callback, handle_list_switches_reply ); will_return( mock_add_message_replied_callback, true ); ret = init_openflow_application_interface( SERVICE_NAME ); assert_true( ret ); assert_true( openflow_application_interface_initialized ); assert_string_equal( service_name, SERVICE_NAME ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } static void test_init_openflow_application_interface_with_too_long_custom_service_name() { bool ret; char too_long_service_name[ MESSENGER_SERVICE_NAME_LENGTH + 1 ]; char expected_service_name[ MESSENGER_SERVICE_NAME_LENGTH ]; memset( too_long_service_name, 'a', sizeof( too_long_service_name ) ); too_long_service_name[ MESSENGER_SERVICE_NAME_LENGTH ] = '\0'; memset( expected_service_name, '\0', sizeof( expected_service_name ) ); ret = init_openflow_application_interface( too_long_service_name ); assert_true( ret == false ); assert_true( openflow_application_interface_initialized == false ); assert_string_equal( service_name, expected_service_name ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } static void test_init_openflow_application_interface_if_already_initialized() { bool ret; ret = set_openflow_event_handlers( EVENT_HANDLERS ); assert_true( ret ); assert_memory_equal( &event_handlers, &EVENT_HANDLERS, sizeof( event_handlers ) ); ret = init_openflow_application_interface( SERVICE_NAME ); assert_true( ret == false ); assert_true( openflow_application_interface_initialized == true ); assert_string_equal( service_name, SERVICE_NAME ); assert_memory_equal( &event_handlers, &EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * init_openflow_application_interface() tests. ********************************************************************************/ static void test_finalize_openflow_application_interface() { bool ret; char expected_service_name[ MESSENGER_SERVICE_NAME_LENGTH ]; memset( expected_service_name, '\0', sizeof( expected_service_name ) ); expect_string( mock_delete_message_received_callback, service_name, SERVICE_NAME ); expect_value( mock_delete_message_received_callback, callback, handle_message ); will_return( mock_delete_message_received_callback, true ); expect_string( mock_delete_message_replied_callback, service_name, SERVICE_NAME ); expect_value( mock_delete_message_replied_callback, callback, handle_list_switches_reply ); will_return( mock_delete_message_replied_callback, true ); ret = finalize_openflow_application_interface(); assert_true( ret ); assert_true( openflow_application_interface_initialized == false ); assert_string_equal( service_name, expected_service_name ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } static void test_finalize_openflow_application_interface_if_not_initialized() { char expected_service_name[ MESSENGER_SERVICE_NAME_LENGTH ]; memset( expected_service_name, '\0', sizeof( expected_service_name ) ); expect_assert_failure( finalize_openflow_application_interface() ); assert_true( openflow_application_interface_initialized == false ); assert_string_equal( service_name, expected_service_name ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_openflow_event_handlers() tests. ********************************************************************************/ static void test_set_openflow_event_handlers() { bool ret; ret = set_openflow_event_handlers( EVENT_HANDLERS ); assert_true( ret ); assert_memory_equal( &event_handlers, &EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * Switch ready handler tests. ********************************************************************************/ static void mock_switch_ready_handler( uint64_t datapath_id, void *user_data ) { check_expected( &datapath_id ); check_expected( user_data ); } static void mock_simple_switch_ready_handler( switch_ready event ) { uint64_t datapath_id = event.datapath_id; void *user_data = event.user_data; check_expected( &datapath_id ); check_expected( user_data ); } static void test_set_switch_ready_handler() { char user_data[] = "Ready!"; set_switch_ready_handler( mock_switch_ready_handler, user_data ); assert_true( event_handlers.switch_ready_callback == mock_switch_ready_handler ); assert_string_equal( event_handlers.switch_ready_user_data, user_data ); } static void test_set_simple_switch_ready_handler() { char user_data[] = "Ready!"; set_switch_ready_handler( mock_simple_switch_ready_handler, user_data ); assert_true( event_handlers.switch_ready_callback == mock_simple_switch_ready_handler ); assert_string_equal( event_handlers.switch_ready_user_data, user_data ); } static void test_set_switch_ready_handler_should_die_if_handler_is_NULL() { char user_data[] = "Ready!"; expect_string( mock_die, format, "Invalid callback function for switch_ready event." ); expect_assert_failure( set_switch_ready_handler( NULL, user_data ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } static void test_handle_switch_ready() { char user_data[] = "Ready!"; buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); uint64_t *datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) ); *datapath_id = htonll( DATAPATH_ID ); expect_memory( mock_switch_ready_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_string( mock_switch_ready_handler, user_data, user_data ); set_switch_ready_handler( mock_switch_ready_handler, user_data ); handle_message( MESSENGER_OPENFLOW_READY, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" ) ); } static void test_handle_switch_ready_with_simple_handler() { char user_data[] = "Ready!"; buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); uint64_t *datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) ); *datapath_id = htonll( DATAPATH_ID ); expect_memory( mock_simple_switch_ready_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_string( mock_simple_switch_ready_handler, user_data, user_data ); set_switch_ready_handler( mock_simple_switch_ready_handler, user_data ); handle_message( MESSENGER_OPENFLOW_READY, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" ) ); } /******************************************************************************** * set_switch_disconnected_handler() tests. ********************************************************************************/ static void test_set_switch_disconnected_handler() { assert_true( set_switch_disconnected_handler( SWITCH_DISCONNECTED_HANDLER, SWITCH_DISCONNECTED_USER_DATA ) ); assert_int_equal( event_handlers.switch_disconnected_callback, SWITCH_DISCONNECTED_HANDLER ); assert_int_equal( event_handlers.switch_disconnected_user_data, SWITCH_DISCONNECTED_USER_DATA ); } static void test_set_switch_disconnected_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( switch_disconnected_handler ) must not be NULL." ); expect_assert_failure( set_switch_disconnected_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_error_handler() tests. ********************************************************************************/ static void test_set_error_handler() { assert_true( set_error_handler( ERROR_HANDLER, ERROR_USER_DATA ) ); assert_int_equal( event_handlers.error_callback, ERROR_HANDLER ); assert_int_equal( event_handlers.error_user_data, ERROR_USER_DATA ); } static void test_set_error_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( error_handler ) must not be NULL." ); expect_assert_failure( set_error_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_echo_reply_handler() tests. ********************************************************************************/ static void test_set_echo_reply_handler() { assert_true( set_echo_reply_handler( ECHO_REPLY_HANDLER, ECHO_REPLY_USER_DATA ) ); assert_int_equal( event_handlers.echo_reply_callback, ECHO_REPLY_HANDLER ); assert_int_equal( event_handlers.echo_reply_user_data, ECHO_REPLY_USER_DATA ); } static void test_set_echo_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( echo_reply_handler ) must not be NULL." ); expect_assert_failure( set_echo_reply_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_vendor_handler() tests. ********************************************************************************/ static void test_set_vendor_handler() { assert_true( set_vendor_handler( VENDOR_HANDLER, VENDOR_USER_DATA ) ); assert_int_equal( event_handlers.vendor_callback, VENDOR_HANDLER ); assert_int_equal( event_handlers.vendor_user_data, VENDOR_USER_DATA ); } static void test_set_vendor_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( vendor_handler ) must not be NULL." ); expect_assert_failure( set_vendor_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_features_reply_handler() tests. ********************************************************************************/ static void test_set_features_reply_handler() { assert_true( set_features_reply_handler( FEATURES_REPLY_HANDLER, FEATURES_REPLY_USER_DATA ) ); assert_int_equal( event_handlers.features_reply_callback, FEATURES_REPLY_HANDLER ); assert_int_equal( event_handlers.features_reply_user_data, FEATURES_REPLY_USER_DATA ); } static void test_set_features_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( features_reply_handler ) must not be NULL." ); expect_assert_failure( set_features_reply_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_get_config_reply_handler() tests. ********************************************************************************/ static void test_set_get_config_reply_handler() { assert_true( set_get_config_reply_handler( GET_CONFIG_REPLY_HANDLER, GET_CONFIG_REPLY_USER_DATA ) ); assert_int_equal( event_handlers.get_config_reply_callback, GET_CONFIG_REPLY_HANDLER ); assert_int_equal( event_handlers.get_config_reply_user_data, GET_CONFIG_REPLY_USER_DATA ); } static void test_set_get_config_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( get_config_reply_handler ) must not be NULL." ); expect_assert_failure( set_get_config_reply_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * Packet in handler tests. ********************************************************************************/ static void mock_packet_in_handler( uint64_t datapath_id, uint32_t transaction_id, uint32_t buffer_id, uint16_t total_len, uint16_t in_port, uint8_t reason, const buffer *data, void *user_data ) { uint32_t total_len32 = total_len; uint32_t in_port32 = in_port; uint32_t reason32 = reason; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( buffer_id ); check_expected( total_len32 ); check_expected( in_port32 ); check_expected( reason32 ); if ( data != NULL ) { check_expected( data->length ); check_expected( data->data ); } else { void *data_uc = ( void * ) ( unsigned long ) data; check_expected( data_uc ); } check_expected( user_data ); packet_in_handler_called = true; } static void mock_simple_packet_in_handler( uint64_t dpid, packet_in event ) { uint64_t datapath_id = dpid; uint32_t transaction_id = event.transaction_id; uint32_t buffer_id = event.buffer_id; uint32_t total_len32 = event.total_len; uint32_t in_port32 = event.in_port; uint32_t reason32 = event.reason; const buffer *data = event.data; void *user_data = event.user_data; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( buffer_id ); check_expected( total_len32 ); check_expected( in_port32 ); check_expected( reason32 ); check_expected( data->length ); check_expected( user_data ); packet_in_handler_called = true; } static void test_set_packet_in_handler() { set_packet_in_handler( mock_packet_in_handler, PACKET_IN_USER_DATA ); assert_true( event_handlers.packet_in_callback == mock_packet_in_handler ); assert_true( event_handlers.packet_in_user_data == PACKET_IN_USER_DATA ); } static void test_set_simple_packet_in_handler() { set_packet_in_handler( mock_simple_packet_in_handler, PACKET_IN_USER_DATA ); assert_true( event_handlers.packet_in_callback == mock_simple_packet_in_handler ); assert_true( event_handlers.packet_in_user_data == PACKET_IN_USER_DATA ); } static void test_set_packet_in_handler_should_die_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function (packet_in_handler) must not be NULL." ); expect_assert_failure( set_packet_in_handler( NULL, PACKET_IN_USER_DATA ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } static void test_handle_packet_in() { uint8_t reason = OFPR_NO_MATCH; uint16_t in_port = 1; uint32_t buffer_id = 0x01020304; buffer *data = alloc_buffer_with_length( 64 ); calloc_packet_info( data ); append_back_buffer( data, 64 ); memset( data->data, 0x01, 64 ); uint16_t total_len = ( uint16_t ) data->length; will_return( mock_parse_packet, true ); expect_memory( mock_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_packet_in_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_packet_in_handler, buffer_id, buffer_id ); expect_value( mock_packet_in_handler, total_len32, ( uint32_t ) total_len ); expect_value( mock_packet_in_handler, in_port32, ( uint32_t ) in_port ); expect_value( mock_packet_in_handler, reason32, ( uint32_t ) reason ); expect_value( mock_packet_in_handler, data->length, data->length ); expect_memory( mock_packet_in_handler, data->data, data->data, data->length ); expect_memory( mock_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN ); set_packet_in_handler( mock_packet_in_handler, USER_DATA ); buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, in_port, reason, data ); handle_packet_in( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_packet_in_with_simple_handler() { uint8_t reason = OFPR_NO_MATCH; uint16_t in_port = 1; uint32_t buffer_id = 0x01020304; buffer *data = alloc_buffer_with_length( 64 ); calloc_packet_info( data ); append_back_buffer( data, 64 ); memset( data->data, 0x01, 64 ); uint16_t total_len = ( uint16_t ) data->length; will_return( mock_parse_packet, true ); expect_memory( mock_simple_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_simple_packet_in_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_simple_packet_in_handler, buffer_id, buffer_id ); expect_value( mock_simple_packet_in_handler, total_len32, ( uint32_t ) total_len ); expect_value( mock_simple_packet_in_handler, in_port32, ( uint32_t ) in_port ); expect_value( mock_simple_packet_in_handler, reason32, ( uint32_t ) reason ); expect_value( mock_simple_packet_in_handler, data->length, data->length ); expect_memory( mock_simple_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN ); set_packet_in_handler( mock_simple_packet_in_handler, USER_DATA ); buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, in_port, reason, data ); handle_packet_in( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_packet_in_with_malformed_packet() { uint8_t reason = OFPR_NO_MATCH; uint16_t in_port = 1; uint32_t buffer_id = 0x01020304; buffer *data = alloc_buffer_with_length( 64 ); calloc_packet_info( data ); append_back_buffer( data, 64 ); memset( data->data, 0x01, 64 ); uint16_t total_len = ( uint16_t ) data->length; buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, in_port, reason, data ); will_return( mock_parse_packet, false ); set_packet_in_handler( mock_packet_in_handler, USER_DATA ); handle_packet_in( DATAPATH_ID, buffer ); assert_false( packet_in_handler_called ); free_buffer( buffer ); } static void test_handle_packet_in_without_data() { uint8_t reason = OFPR_NO_MATCH; uint16_t in_port = 1; uint32_t buffer_id = 0x01020304; buffer *data = alloc_buffer_with_length( 64 ); append_back_buffer( data, 64 ); memset( data->data, 0x01, 64 ); uint16_t total_len = ( uint16_t ) data->length; expect_memory( mock_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_packet_in_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_packet_in_handler, buffer_id, buffer_id ); expect_value( mock_packet_in_handler, total_len32, ( uint32_t ) total_len ); expect_value( mock_packet_in_handler, in_port32, ( uint32_t ) in_port ); expect_value( mock_packet_in_handler, reason32, ( uint32_t ) reason ); expect_value( mock_packet_in_handler, data_uc, NULL ); expect_memory( mock_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN ); set_packet_in_handler( mock_packet_in_handler, USER_DATA ); buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, in_port, reason, NULL ); handle_packet_in( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_packet_in_without_handler() { uint8_t reason = OFPR_NO_MATCH; uint16_t in_port = 1; uint32_t buffer_id = 0x01020304; buffer *data = alloc_buffer_with_length( 64 ); append_back_buffer( data, 64 ); memset( data->data, 0x01, 64 ); uint16_t total_len = ( uint16_t ) data->length; buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, in_port, reason, data ); handle_packet_in( DATAPATH_ID, buffer ); assert_false( packet_in_handler_called ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_packet_in_should_die_if_message_is_NULL() { expect_string( mock_die, format, "handle_packet_in(): packet_in message should not be empty." ); set_packet_in_handler( mock_packet_in_handler, USER_DATA ); expect_assert_failure( handle_packet_in( DATAPATH_ID, NULL ) ); } static void test_handle_packet_in_should_die_if_message_length_is_zero() { buffer *buffer = alloc_buffer_with_length( 32 ); expect_string( mock_die, format, "handle_packet_in(): packet_in message should not be empty." ); set_packet_in_handler( mock_packet_in_handler, USER_DATA ); expect_assert_failure( handle_packet_in( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * set_flow_removed_handler() tests. ********************************************************************************/ static void mock_simple_flow_removed_handler( uint64_t datapath_id, flow_removed message ) { uint32_t transaction_id = message.transaction_id; struct ofp_match match = message.match; uint64_t cookie = message.cookie; uint32_t priority32 = message.priority; uint32_t reason32 = message.reason; uint32_t duration_sec = message.duration_sec; uint32_t duration_nsec = message.duration_nsec; uint32_t idle_timeout32 = message.idle_timeout; uint64_t packet_count = message.packet_count; uint64_t byte_count = message.byte_count; void *user_data = message.user_data; check_expected( &datapath_id ); check_expected( transaction_id ); check_expected( &match ); check_expected( &cookie ); check_expected( priority32 ); check_expected( reason32 ); check_expected( duration_sec ); check_expected( duration_nsec ); check_expected( idle_timeout32 ); check_expected( &packet_count ); check_expected( &byte_count ); check_expected( user_data ); } static void test_set_flow_removed_handler() { set_flow_removed_handler( mock_flow_removed_handler, FLOW_REMOVED_USER_DATA ); assert_true( event_handlers.flow_removed_callback == mock_flow_removed_handler ); assert_true( event_handlers.flow_removed_user_data == FLOW_REMOVED_USER_DATA ); } static void test_set_simple_flow_removed_handler() { set_flow_removed_handler( mock_simple_flow_removed_handler, FLOW_REMOVED_USER_DATA ); assert_true( event_handlers.flow_removed_callback == mock_simple_flow_removed_handler ); assert_true( event_handlers.flow_removed_user_data == FLOW_REMOVED_USER_DATA ); } static void test_set_flow_removed_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function (flow_removed_handler) must not be NULL." ); expect_assert_failure( set_flow_removed_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_port_status_handler() tests. ********************************************************************************/ static void test_set_port_status_handler() { assert_true( set_port_status_handler( PORT_STATUS_HANDLER, PORT_STATUS_USER_DATA ) ); assert_int_equal( event_handlers.port_status_callback, PORT_STATUS_HANDLER ); assert_int_equal( event_handlers.port_status_user_data, PORT_STATUS_USER_DATA ); } static void test_set_port_status_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( port_status_handler ) must not be NULL." ); expect_assert_failure( set_port_status_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_stats_reply_handler() tests. ********************************************************************************/ static void test_set_stats_reply_handler() { assert_true( set_stats_reply_handler( STATS_REPLY_HANDLER, STATS_REPLY_USER_DATA ) ); assert_int_equal( event_handlers.stats_reply_callback, STATS_REPLY_HANDLER ); assert_int_equal( event_handlers.stats_reply_user_data, STATS_REPLY_USER_DATA ); } static void test_set_stats_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( stats_reply_handler ) must not be NULL." ); expect_assert_failure( set_stats_reply_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_barrier_reply_handler() tests. ********************************************************************************/ static void test_set_barrier_reply_handler() { assert_true( set_barrier_reply_handler( BARRIER_REPLY_HANDLER, BARRIER_REPLY_USER_DATA ) ); assert_int_equal( event_handlers.barrier_reply_callback, BARRIER_REPLY_HANDLER ); assert_int_equal( event_handlers.barrier_reply_user_data, BARRIER_REPLY_USER_DATA ); } static void test_set_barrier_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( barrier_reply_handler ) must not be NULL." ); expect_assert_failure( set_barrier_reply_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_queue_get_config_reply_handler() tests. ********************************************************************************/ static void test_set_queue_get_config_reply_handler() { assert_true( set_queue_get_config_reply_handler( QUEUE_GET_CONFIG_REPLY_HANDLER, QUEUE_GET_CONFIG_REPLY_USER_DATA ) ); assert_int_equal( event_handlers.queue_get_config_reply_callback, QUEUE_GET_CONFIG_REPLY_HANDLER ); assert_int_equal( event_handlers.queue_get_config_reply_user_data, QUEUE_GET_CONFIG_REPLY_USER_DATA ); } static void test_set_queue_get_config_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( queue_get_config_reply_handler ) must not be NULL." ); expect_assert_failure( set_queue_get_config_reply_handler( NULL, NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * set_list_switches_reply_handler() tests. ********************************************************************************/ static void test_set_list_switches_reply_handler() { assert_true( set_list_switches_reply_handler( LIST_SWITCHES_REPLY_HANDLER ) ); assert_int_equal( event_handlers.list_switches_reply_callback, LIST_SWITCHES_REPLY_HANDLER ); } static void test_set_list_switches_reply_handler_if_handler_is_NULL() { expect_string( mock_die, format, "Callback function ( list_switches_reply_handler ) must not be NULL." ); expect_assert_failure( set_list_switches_reply_handler( NULL ) ); assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) ); } /******************************************************************************** * send_openflow_message() tests. ********************************************************************************/ static void test_send_openflow_message() { void *expected_data; bool ret; size_t expected_length, header_length; buffer *buffer; openflow_service_header_t *header; buffer = create_hello( TRANSACTION_ID ); assert_true( buffer != NULL ); header_length = ( size_t ) ( sizeof( openflow_service_header_t ) + strlen( SERVICE_NAME ) + 1 ); expected_length = ( size_t ) ( header_length + sizeof( struct ofp_header ) ); expected_data = xcalloc( 1, expected_length ); header = expected_data; header->datapath_id = htonll( DATAPATH_ID ); header->service_name_length = htons( ( uint16_t ) ( strlen( SERVICE_NAME ) + 1 ) ); memcpy( ( char * ) expected_data + sizeof( openflow_service_header_t ), SERVICE_NAME, strlen( SERVICE_NAME ) + 1 ); memcpy( ( char * ) expected_data + header_length, buffer->data, buffer->length ); expect_string( mock_send_message, service_name, REMOTE_SERVICE_NAME ); expect_value( mock_send_message, tag32, MESSENGER_OPENFLOW_MESSAGE ); expect_value( mock_send_message, len, expected_length ); expect_memory( mock_send_message, data, expected_data, expected_length ); will_return( mock_send_message, true ); ret = send_openflow_message( DATAPATH_ID, buffer ); assert_true( ret ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.hello_send_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( buffer ); xfree( expected_data ); xfree( delete_hash_entry( stats, "openflow_application_interface.hello_send_succeeded" ) ); } static void test_send_openflow_message_if_message_is_NULL() { expect_assert_failure( send_openflow_message( DATAPATH_ID, NULL ) ); } static void test_send_openflow_message_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 128 ); assert_true( buffer != NULL ); expect_assert_failure( send_openflow_message( DATAPATH_ID, NULL ) ); free_buffer( buffer ); } /******************************************************************************** * handle_error() tests. ********************************************************************************/ static void test_handle_error() { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_error( TRANSACTION_ID, OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE, data ); expect_memory( mock_error_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_error_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_error_handler, type32, OFPET_HELLO_FAILED ); expect_value( mock_error_handler, code32, OFPHFC_INCOMPATIBLE ); expect_value( mock_error_handler, data->length, data->length ); expect_memory( mock_error_handler, data->data, data->data, data->length ); expect_memory( mock_error_handler, user_data, USER_DATA, USER_DATA_LEN ); set_error_handler( mock_error_handler, USER_DATA ); handle_error( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_error_if_handler_is_not_registered() { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_error( TRANSACTION_ID, OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE, data ); // FIXME handle_error( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_error_if_message_is_NULL() { set_error_handler( mock_error_handler, USER_DATA ); expect_assert_failure( handle_error( DATAPATH_ID, NULL ) ); } static void test_handle_error_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_error_handler( mock_error_handler, USER_DATA ); expect_assert_failure( handle_error( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_echo_request() tests. ********************************************************************************/ static void test_handle_echo_reply() { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_echo_reply( TRANSACTION_ID, data ); expect_memory( mock_echo_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_echo_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_echo_reply_handler, data->length, data->length ); expect_memory( mock_echo_reply_handler, data->data, data->data, data->length ); expect_memory( mock_echo_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_echo_reply_handler( mock_echo_reply_handler, USER_DATA ); handle_echo_reply( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_echo_reply_without_data() { buffer *buffer; buffer = create_echo_reply( TRANSACTION_ID, NULL ); expect_memory( mock_echo_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_echo_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_echo_reply_handler, data_uc, NULL ); expect_memory( mock_echo_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_echo_reply_handler( mock_echo_reply_handler, USER_DATA ); handle_echo_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_echo_reply_if_handler_is_not_registered() { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_echo_reply( TRANSACTION_ID, data ); // FIXME handle_echo_reply( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_echo_reply_if_message_is_NULL() { set_echo_reply_handler( mock_echo_reply_handler, USER_DATA ); expect_assert_failure( handle_echo_reply( DATAPATH_ID, NULL ) ); } static void test_handle_echo_reply_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_echo_reply_handler( mock_echo_reply_handler, USER_DATA ); expect_assert_failure( handle_echo_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_vendor() tests. ********************************************************************************/ static void test_handle_vendor() { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_vendor( TRANSACTION_ID, VENDOR_ID, data ); expect_memory( mock_vendor_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_vendor_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_vendor_handler, vendor, VENDOR_ID ); expect_value( mock_vendor_handler, data->length, data->length ); expect_memory( mock_vendor_handler, data->data, data->data, data->length ); expect_memory( mock_vendor_handler, user_data, USER_DATA, USER_DATA_LEN ); set_vendor_handler( mock_vendor_handler, USER_DATA ); handle_vendor( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_vendor_without_data() { buffer *buffer; buffer = create_vendor( TRANSACTION_ID, VENDOR_ID, NULL ); expect_memory( mock_vendor_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_vendor_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_vendor_handler, vendor, VENDOR_ID ); expect_value( mock_vendor_handler, data_uc, NULL ); expect_memory( mock_vendor_handler, user_data, USER_DATA, USER_DATA_LEN ); set_vendor_handler( mock_vendor_handler, USER_DATA ); handle_vendor( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_vendor_if_handler_is_not_registered() { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_vendor( TRANSACTION_ID, VENDOR_ID, data ); // FIXME handle_vendor( DATAPATH_ID, buffer ); free_buffer( data ); free_buffer( buffer ); } static void test_handle_vendor_if_message_is_NULL() { set_vendor_handler( mock_vendor_handler, USER_DATA ); expect_assert_failure( handle_vendor( DATAPATH_ID, NULL ) ); } static void test_handle_vendor_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_vendor_handler( mock_vendor_handler, USER_DATA ); expect_assert_failure( handle_vendor( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_features_reply() tests. ********************************************************************************/ static void test_handle_features_reply() { uint8_t n_tables = 2; uint32_t n_buffers = 1024; uint32_t capabilities; uint32_t actions; struct ofp_phy_port *phy_port[ 2 ]; buffer *buffer; list_element *ports; capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP ); actions = ( ( 1 << OFPAT_OUTPUT ) | ( 1 << OFPAT_SET_VLAN_VID ) | ( 1 << OFPAT_SET_TP_SRC ) | ( 1 << OFPAT_SET_TP_DST ) ); phy_port[ 0 ] = xcalloc( 1, sizeof( struct ofp_phy_port ) ); phy_port[ 1 ] = xcalloc( 1, sizeof( struct ofp_phy_port ) ); phy_port[ 0 ]->port_no = 1; memcpy( phy_port[ 0 ]->hw_addr, MAC_ADDR_X, sizeof( phy_port[ 0 ]->hw_addr ) ); memset( phy_port[ 0 ]->name, '\0', OFP_MAX_PORT_NAME_LEN ); memcpy( phy_port[ 0 ]->name, PORT_NAME, strlen( PORT_NAME ) ); phy_port[ 0 ]->config = OFPPC_PORT_DOWN; phy_port[ 0 ]->state = OFPPS_LINK_DOWN; phy_port[ 0 ]->curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE ); phy_port[ 0 ]->advertised = PORT_FEATURES; phy_port[ 0 ]->supported = PORT_FEATURES; phy_port[ 0 ]->peer = PORT_FEATURES; memcpy( phy_port[ 1 ], phy_port [ 0 ], sizeof( struct ofp_phy_port ) ); phy_port[ 1 ]->port_no = 2; memcpy( phy_port[ 1 ]->hw_addr, MAC_ADDR_Y, sizeof( phy_port[ 1 ]->hw_addr ) ); create_list( &ports ); append_to_tail( &ports, phy_port[ 0 ] ); append_to_tail( &ports, phy_port[ 1 ] ); buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables, capabilities, actions, ports ); expect_memory( mock_features_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_features_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_features_reply_handler, n_buffers, n_buffers ); expect_value( mock_features_reply_handler, n_tables32, ( uint32_t ) n_tables ); expect_value( mock_features_reply_handler, capabilities, capabilities ); expect_value( mock_features_reply_handler, actions, actions ); expect_memory( mock_features_reply_handler, port1, ports->data, sizeof( struct ofp_phy_port ) ); expect_memory( mock_features_reply_handler, port2, ports->next->data, sizeof( struct ofp_phy_port ) ); expect_memory( mock_features_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_features_reply_handler( mock_features_reply_handler, USER_DATA ); handle_features_reply( DATAPATH_ID, buffer ); xfree( phy_port[ 0 ] ); xfree( phy_port[ 1 ] ); delete_list( ports ); free_buffer( buffer ); } static void test_handle_features_reply_without_phy_port() { uint8_t n_tables = 2; uint32_t n_buffers = 1024; uint32_t capabilities; uint32_t actions; buffer *buffer; capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP ); actions = ( ( 1 << OFPAT_OUTPUT ) | ( 1 << OFPAT_SET_VLAN_VID ) | ( 1 << OFPAT_SET_TP_SRC ) | ( 1 << OFPAT_SET_TP_DST ) ); buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables, capabilities, actions, NULL ); expect_memory( mock_features_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_features_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_features_reply_handler, n_buffers, n_buffers ); expect_value( mock_features_reply_handler, n_tables32, ( uint32_t ) n_tables ); expect_value( mock_features_reply_handler, capabilities, capabilities ); expect_value( mock_features_reply_handler, actions, actions ); expect_value( mock_features_reply_handler, phy_ports_uc, NULL ); expect_memory( mock_features_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_features_reply_handler( mock_features_reply_handler, USER_DATA ); handle_features_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_features_reply_if_handler_is_not_registered() { uint8_t n_tables = 2; uint32_t n_buffers = 1024; uint32_t capabilities; uint32_t actions; struct ofp_phy_port *phy_port[ 2 ]; buffer *buffer; list_element *ports; capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP ); actions = ( ( 1 << OFPAT_OUTPUT ) | ( 1 << OFPAT_SET_VLAN_VID ) | ( 1 << OFPAT_SET_TP_SRC ) | ( 1 << OFPAT_SET_TP_DST ) ); phy_port[ 0 ] = xcalloc( 1, sizeof( struct ofp_phy_port ) ); phy_port[ 1 ] = xcalloc( 1, sizeof( struct ofp_phy_port ) ); phy_port[ 0 ]->port_no = 1; memcpy( phy_port[ 0 ]->hw_addr, MAC_ADDR_X, sizeof( phy_port[ 0 ]->hw_addr ) ); memset( phy_port[ 0 ]->name, '\0', OFP_MAX_PORT_NAME_LEN ); memcpy( phy_port[ 0 ]->name, PORT_NAME, strlen( PORT_NAME ) ); phy_port[ 0 ]->config = OFPPC_PORT_DOWN; phy_port[ 0 ]->state = OFPPS_LINK_DOWN; phy_port[ 0 ]->curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE ); phy_port[ 0 ]->advertised = PORT_FEATURES; phy_port[ 0 ]->supported = PORT_FEATURES; phy_port[ 0 ]->peer = PORT_FEATURES; memcpy( phy_port[ 1 ], phy_port [ 0 ], sizeof( struct ofp_phy_port ) ); phy_port[ 1 ]->port_no = 2; memcpy( phy_port[ 1 ]->hw_addr, MAC_ADDR_Y, sizeof( phy_port[ 1 ]->hw_addr ) ); create_list( &ports ); append_to_tail( &ports, phy_port[ 0 ] ); append_to_tail( &ports, phy_port[ 1 ] ); buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables, capabilities, actions, ports ); // FIXME handle_features_reply( DATAPATH_ID, buffer ); xfree( phy_port[ 0 ] ); xfree( phy_port[ 1 ] ); delete_list( ports ); free_buffer( buffer ); } static void test_handle_features_reply_if_message_is_NULL() { set_features_reply_handler( mock_features_reply_handler, USER_DATA ); expect_assert_failure( handle_features_reply( DATAPATH_ID, NULL ) ); } static void test_handle_features_reply_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_features_reply_handler( mock_features_reply_handler, USER_DATA ); expect_assert_failure( handle_features_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_get_config_reply() tests. ********************************************************************************/ static void test_handle_get_config_reply() { uint16_t flags = OFPC_FRAG_NORMAL; uint16_t miss_send_len = 128; buffer *buffer; buffer = create_get_config_reply( TRANSACTION_ID, flags, miss_send_len ); expect_memory( mock_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_get_config_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_get_config_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_get_config_reply_handler, miss_send_len32, ( uint32_t ) miss_send_len ); expect_memory( mock_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA ); handle_get_config_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_get_config_reply_if_handler_is_not_registered() { uint16_t flags = OFPC_FRAG_NORMAL; uint16_t miss_send_len = 128; buffer *buffer; buffer = create_get_config_reply( TRANSACTION_ID, flags, miss_send_len ); // FIXME handle_get_config_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_get_config_reply_if_message_is_NULL() { set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA ); expect_assert_failure( handle_get_config_reply( DATAPATH_ID, NULL ) ); } static void test_handle_get_config_reply_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA ); expect_assert_failure( handle_get_config_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_flow_removed() tests. ********************************************************************************/ static void test_handle_flow_removed() { uint8_t reason = OFPRR_IDLE_TIMEOUT; uint16_t idle_timeout = 60; uint16_t priority = UINT16_MAX; uint32_t duration_sec = 180; uint32_t duration_nsec = 10000; uint64_t cookie = 0x0102030405060708ULL; uint64_t packet_count = 1000; uint64_t byte_count = 100000; buffer *buffer = create_flow_removed( TRANSACTION_ID, MATCH, cookie, priority, reason, duration_sec, duration_nsec, idle_timeout, packet_count, byte_count ); expect_memory( mock_flow_removed_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_flow_removed_handler, transaction_id, TRANSACTION_ID ); expect_memory( mock_flow_removed_handler, &match, &MATCH, sizeof( struct ofp_match ) ); expect_memory( mock_flow_removed_handler, &cookie, &cookie, sizeof( uint64_t ) ); expect_value( mock_flow_removed_handler, priority32, ( uint32_t ) priority ); expect_value( mock_flow_removed_handler, reason32, ( uint32_t ) reason ); expect_value( mock_flow_removed_handler, duration_sec, duration_sec ); expect_value( mock_flow_removed_handler, duration_nsec, duration_nsec ); expect_value( mock_flow_removed_handler, idle_timeout32, ( uint32_t ) idle_timeout ); expect_memory( mock_flow_removed_handler, &packet_count, &packet_count, sizeof( uint64_t ) ); expect_memory( mock_flow_removed_handler, &byte_count, &byte_count, sizeof( uint64_t ) ); expect_memory( mock_flow_removed_handler, user_data, USER_DATA, USER_DATA_LEN ); set_flow_removed_handler( mock_flow_removed_handler, USER_DATA ); handle_flow_removed( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_flow_removed_with_simple_handler() { uint8_t reason = OFPRR_IDLE_TIMEOUT; uint16_t idle_timeout = 60; uint16_t priority = UINT16_MAX; uint32_t duration_sec = 180; uint32_t duration_nsec = 10000; uint64_t cookie = 0x0102030405060708ULL; uint64_t packet_count = 1000; uint64_t byte_count = 100000; buffer *buffer = create_flow_removed( TRANSACTION_ID, MATCH, cookie, priority, reason, duration_sec, duration_nsec, idle_timeout, packet_count, byte_count ); expect_memory( mock_simple_flow_removed_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_simple_flow_removed_handler, transaction_id, TRANSACTION_ID ); expect_memory( mock_simple_flow_removed_handler, &match, &MATCH, sizeof( struct ofp_match ) ); expect_memory( mock_simple_flow_removed_handler, &cookie, &cookie, sizeof( uint64_t ) ); expect_value( mock_simple_flow_removed_handler, priority32, ( uint32_t ) priority ); expect_value( mock_simple_flow_removed_handler, reason32, ( uint32_t ) reason ); expect_value( mock_simple_flow_removed_handler, duration_sec, duration_sec ); expect_value( mock_simple_flow_removed_handler, duration_nsec, duration_nsec ); expect_value( mock_simple_flow_removed_handler, idle_timeout32, ( uint32_t ) idle_timeout ); expect_memory( mock_simple_flow_removed_handler, &packet_count, &packet_count, sizeof( uint64_t ) ); expect_memory( mock_simple_flow_removed_handler, &byte_count, &byte_count, sizeof( uint64_t ) ); expect_memory( mock_simple_flow_removed_handler, user_data, USER_DATA, USER_DATA_LEN ); set_flow_removed_handler( mock_simple_flow_removed_handler, USER_DATA ); handle_flow_removed( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_flow_removed_if_handler_is_not_registered() { uint8_t reason = OFPRR_IDLE_TIMEOUT; uint16_t idle_timeout = 60; uint16_t priority = UINT16_MAX; uint32_t duration_sec = 180; uint32_t duration_nsec = 10000; uint64_t cookie = 0x0102030405060708ULL; uint64_t packet_count = 1000; uint64_t byte_count = 100000; buffer *buffer; buffer = create_flow_removed( TRANSACTION_ID, MATCH, cookie, priority, reason, duration_sec, duration_nsec, idle_timeout, packet_count, byte_count ); // FIXME handle_flow_removed( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_flow_removed_if_message_is_NULL() { set_flow_removed_handler( mock_flow_removed_handler, USER_DATA ); expect_assert_failure( handle_flow_removed( DATAPATH_ID, NULL ) ); } static void test_handle_flow_removed_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_flow_removed_handler( mock_flow_removed_handler, USER_DATA ); expect_assert_failure( handle_flow_removed( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_port_status() tests. ********************************************************************************/ static void test_handle_port_status() { uint8_t reason = OFPPR_MODIFY; buffer *buffer; struct ofp_phy_port desc; desc.port_no = 1; memcpy( desc.hw_addr, MAC_ADDR_X, sizeof( desc.hw_addr ) ); memset( desc.name, '\0', OFP_MAX_PORT_NAME_LEN ); memcpy( desc.name, PORT_NAME, strlen( PORT_NAME ) ); desc.config = OFPPC_PORT_DOWN; desc.state = OFPPS_LINK_DOWN; desc.curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE ); desc.advertised = PORT_FEATURES; desc.supported = PORT_FEATURES; desc.peer = PORT_FEATURES; buffer = create_port_status( TRANSACTION_ID, reason, desc ); expect_memory( mock_port_status_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_port_status_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_port_status_handler, reason32, ( uint32_t ) reason ); expect_memory( mock_port_status_handler, &phy_port, &desc, sizeof( struct ofp_phy_port ) ); expect_memory( mock_port_status_handler, user_data, USER_DATA, USER_DATA_LEN ); set_port_status_handler( mock_port_status_handler, USER_DATA ); handle_port_status( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_port_status_if_handler_is_not_registered() { uint8_t reason = OFPPR_MODIFY; buffer *buffer; struct ofp_phy_port desc; desc.port_no = 1; memcpy( desc.hw_addr, MAC_ADDR_X, sizeof( desc.hw_addr ) ); memset( desc.name, '\0', OFP_MAX_PORT_NAME_LEN ); memcpy( desc.name, PORT_NAME, strlen( PORT_NAME ) ); desc.config = OFPPC_PORT_DOWN; desc.state = OFPPS_LINK_DOWN; desc.curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE ); desc.advertised = PORT_FEATURES; desc.supported = PORT_FEATURES; desc.peer = PORT_FEATURES; buffer = create_port_status( TRANSACTION_ID, reason, desc ); // FIXME handle_port_status( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_port_status_if_message_is_NULL() { set_port_status_handler( mock_port_status_handler, USER_DATA ); expect_assert_failure( handle_port_status( DATAPATH_ID, NULL ) ); } static void test_handle_port_status_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_port_status_handler( mock_port_status_handler, USER_DATA ); expect_assert_failure( handle_port_status( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_stats_reply() tests. ********************************************************************************/ static void test_handle_stats_reply_if_type_is_OFPST_DESC() { char mfr_desc[ DESC_STR_LEN ]; char hw_desc[ DESC_STR_LEN ]; char sw_desc[ DESC_STR_LEN ]; char serial_num[ SERIAL_NUM_LEN ]; char dp_desc[ DESC_STR_LEN ]; uint16_t flags = 0; uint32_t body_len; buffer *buffer; struct ofp_stats_reply *stats_reply; memset( mfr_desc, '\0', DESC_STR_LEN ); memset( hw_desc, '\0', DESC_STR_LEN ); memset( sw_desc, '\0', DESC_STR_LEN ); memset( serial_num, '\0', SERIAL_NUM_LEN ); memset( dp_desc, '\0', DESC_STR_LEN ); sprintf( mfr_desc, "NEC Coporation" ); sprintf( hw_desc, "OpenFlow Switch Hardware" ); sprintf( sw_desc, "OpenFlow Switch Software" ); sprintf( serial_num, "123456" ); sprintf( dp_desc, "Datapath 0" ); buffer = create_desc_stats_reply( TRANSACTION_ID, flags, mfr_desc, hw_desc, sw_desc, serial_num, dp_desc ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_DESC ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, stats_reply->body, body_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_stats_reply_if_type_is_OFPST_FLOW() { void *expected_data; uint16_t flags = OFPSF_REPLY_MORE; uint16_t stats_len; uint32_t body_len; buffer *buffer; list_element *flow_stats; struct ofp_stats_reply *stats_reply; struct ofp_flow_stats *stats[ 2 ]; struct ofp_action_output *action; stats_len = offsetof( struct ofp_flow_stats, actions ) + sizeof( struct ofp_action_output ); stats[ 0 ] = xcalloc( 1, stats_len ); stats[ 1 ] = xcalloc( 1, stats_len ); stats[ 0 ]->length = stats_len; stats[ 0 ]->table_id = 1; stats[ 0 ]->pad = 0; stats[ 0 ]->match = MATCH; stats[ 0 ]->duration_sec = 60; stats[ 0 ]->duration_nsec = 10000; stats[ 0 ]->priority = 1024; stats[ 0 ]->idle_timeout = 60; stats[ 0 ]->hard_timeout = 3600; stats[ 0 ]->cookie = 0x0102030405060708ULL; stats[ 0 ]->packet_count = 1000; stats[ 0 ]->byte_count = 100000; action = ( struct ofp_action_output * ) stats[ 0 ]->actions; action->type = OFPAT_OUTPUT; action->len = 8; action->port = 1; action->max_len = 2048; memcpy( stats[ 1 ], stats[ 0 ], stats_len ); stats[ 1 ]->cookie = 0x0203040506070809ULL; action = ( struct ofp_action_output * ) stats[ 1 ]->actions; action->port = 2; create_list( &flow_stats ); append_to_tail( &flow_stats, stats[ 0 ] ); append_to_tail( &flow_stats, stats[ 1 ] ); expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) ); memcpy( expected_data, stats[ 0 ], stats_len ); memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len ); buffer = create_flow_stats_reply( TRANSACTION_ID, flags, flow_stats ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_FLOW ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, expected_data, stats_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); xfree( stats[ 0 ] ); xfree( stats[ 1 ] ); delete_list( flow_stats ); xfree( expected_data ); free_buffer( buffer ); } static void test_handle_stats_reply_if_type_is_OFPST_AGGREGATE() { uint16_t flags = 0; uint32_t body_len; uint32_t flow_count = 1000; uint64_t packet_count = 1000; uint64_t byte_count = 10000; buffer *buffer; struct ofp_stats_reply *stats_reply; struct ofp_aggregate_stats_reply aggregate_stats_reply; buffer = create_aggregate_stats_reply( TRANSACTION_ID, flags, packet_count, byte_count, flow_count ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_AGGREGATE ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); ntoh_aggregate_stats( &aggregate_stats_reply, ( struct ofp_aggregate_stats_reply * ) stats_reply->body ); expect_memory( mock_stats_reply_handler, data->data, &aggregate_stats_reply, body_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_stats_reply_if_type_is_OFPST_TABLE() { void *expected_data; uint16_t flags = OFPSF_REPLY_MORE; uint16_t stats_len; uint32_t body_len; buffer *buffer; list_element *table_stats; struct ofp_stats_reply *stats_reply; struct ofp_table_stats *stats[ 2 ]; stats_len = sizeof( struct ofp_table_stats ); stats[ 0 ] = xcalloc( 1, stats_len ); stats[ 1 ] = xcalloc( 1, stats_len ); stats[ 0 ]->table_id = 1; sprintf( stats[ 0 ]->name, "Table 1" ); stats[ 0 ]->wildcards = OFPFW_ALL; stats[ 0 ]->max_entries = 10000; stats[ 0 ]->active_count = 1000; stats[ 0 ]->lookup_count = 100000; stats[ 0 ]->matched_count = 10000; memcpy( stats[ 1 ], stats[ 0 ], stats_len ); stats[ 1 ]->table_id = 2; sprintf( stats[ 1 ]->name, "Table 2" ); create_list( &table_stats ); append_to_tail( &table_stats, stats[ 0 ] ); append_to_tail( &table_stats, stats[ 1 ] ); expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) ); memcpy( expected_data, stats[ 0 ], stats_len ); memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len ); buffer = create_table_stats_reply( TRANSACTION_ID, flags, table_stats ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_TABLE ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, expected_data, stats_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); xfree( stats[ 0 ] ); xfree( stats[ 1 ] ); delete_list( table_stats ); xfree( expected_data ); free_buffer( buffer ); } static void test_handle_stats_reply_if_type_is_OFPST_PORT() { void *expected_data; uint16_t flags = OFPSF_REPLY_MORE; uint16_t stats_len; uint32_t body_len; buffer *buffer; list_element *port_stats; struct ofp_stats_reply *stats_reply; struct ofp_port_stats *stats[ 2 ]; stats_len = sizeof( struct ofp_port_stats ); stats[ 0 ] = xcalloc( 1, stats_len ); stats[ 1 ] = xcalloc( 1, stats_len ); stats[ 0 ]->port_no = 1; stats[ 0 ]->rx_packets = 10000; stats[ 0 ]->tx_packets = 20000; stats[ 0 ]->rx_bytes = 30000; stats[ 0 ]->tx_bytes = 40000; stats[ 0 ]->rx_dropped = 50000; stats[ 0 ]->tx_dropped = 60000; stats[ 0 ]->rx_errors = 70000; stats[ 0 ]->tx_errors = 80000; stats[ 0 ]->rx_frame_err = 1; stats[ 0 ]->rx_over_err = 2; stats[ 0 ]->rx_crc_err = 1; stats[ 0 ]->collisions = 3; memcpy( stats[ 1 ], stats[ 0 ], stats_len ); stats[ 1 ]->port_no = 2; create_list( &port_stats ); append_to_tail( &port_stats, stats[ 0 ] ); append_to_tail( &port_stats, stats[ 1 ] ); expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) ); memcpy( expected_data, stats[ 0 ], stats_len ); memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len ); buffer = create_port_stats_reply( TRANSACTION_ID, flags, port_stats ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_PORT ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, expected_data, stats_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); xfree( stats[ 0 ] ); xfree( stats[ 1 ] ); delete_list( port_stats ); xfree( expected_data ); free_buffer( buffer ); } static void test_handle_stats_reply_if_type_is_OFPST_QUEUE() { void *expected_data; uint16_t flags = OFPSF_REPLY_MORE; uint16_t stats_len; uint32_t body_len; buffer *buffer; list_element *queue_stats; struct ofp_stats_reply *stats_reply; struct ofp_queue_stats *stats[ 2 ]; stats_len = sizeof( struct ofp_queue_stats ); stats[ 0 ] = xcalloc( 1, stats_len ); stats[ 1 ] = xcalloc( 1, stats_len ); stats[ 0 ]->port_no = 1; stats[ 0 ]->queue_id = 2; stats[ 0 ]->tx_bytes = 100000; stats[ 0 ]->tx_packets = 60000; stats[ 0 ]->tx_errors = 80; memcpy( stats[ 1 ], stats[ 0 ], stats_len ); stats[ 1 ]->queue_id = 3; create_list( &queue_stats ); append_to_tail( &queue_stats, stats[ 0 ] ); append_to_tail( &queue_stats, stats[ 1 ] ); expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) ); memcpy( expected_data, stats[ 0 ], stats_len ); memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len ); buffer = create_queue_stats_reply( TRANSACTION_ID, flags, queue_stats ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_QUEUE ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, expected_data, stats_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); xfree( stats[ 0 ] ); xfree( stats[ 1 ] ); delete_list( queue_stats ); xfree( expected_data ); free_buffer( buffer ); } static void test_handle_stats_reply_if_type_is_OFPST_VENDOR() { void *expected_data; uint16_t flags = 0; uint32_t body_len; uint32_t vendor = VENDOR_ID; buffer *buffer, *body; struct ofp_stats_reply *stats_reply; body = alloc_buffer_with_length( 128 ); append_back_buffer( body, 128 ); memset( body->data, 0xa1, body->length ); expected_data = xcalloc( 1, ( size_t ) ( body->length + sizeof( uint32_t ) ) ); memcpy( expected_data, &vendor, sizeof( uint32_t ) ); memcpy( ( char * ) expected_data + sizeof( uint32_t ), body->data, body->length ); buffer = create_vendor_stats_reply( TRANSACTION_ID, flags, vendor, body ); stats_reply = buffer->data; body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_VENDOR ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, expected_data, body_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_stats_reply( DATAPATH_ID, buffer ); xfree( expected_data ); free_buffer( body ); free_buffer( buffer ); } static void test_handle_stats_reply_with_undefined_type() { uint16_t flags = 0; uint32_t vendor = VENDOR_ID; buffer *buffer; struct ofp_stats_reply *stats_reply; buffer = create_vendor_stats_reply( TRANSACTION_ID, flags, vendor, NULL ); stats_reply = buffer->data; stats_reply->type = htons( 0xfffe ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); expect_assert_failure( handle_stats_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } static void test_handle_stats_reply_if_handler_is_not_registered() { char mfr_desc[ DESC_STR_LEN ]; char hw_desc[ DESC_STR_LEN ]; char sw_desc[ DESC_STR_LEN ]; char serial_num[ SERIAL_NUM_LEN ]; char dp_desc[ DESC_STR_LEN ]; uint16_t flags = 0; buffer *buffer; memset( mfr_desc, '\0', DESC_STR_LEN ); memset( hw_desc, '\0', DESC_STR_LEN ); memset( sw_desc, '\0', DESC_STR_LEN ); memset( serial_num, '\0', SERIAL_NUM_LEN ); memset( dp_desc, '\0', DESC_STR_LEN ); sprintf( mfr_desc, "NEC Coporation" ); sprintf( hw_desc, "OpenFlow Switch Hardware" ); sprintf( sw_desc, "OpenFlow Switch Software" ); sprintf( serial_num, "123456" ); sprintf( dp_desc, "Datapath 0" ); buffer = create_desc_stats_reply( TRANSACTION_ID, flags, mfr_desc, hw_desc, sw_desc, serial_num, dp_desc ); // FIXME handle_stats_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_stats_reply_if_message_is_NULL() { set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); expect_assert_failure( handle_stats_reply( DATAPATH_ID, NULL ) ); } static void test_handle_stats_reply_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); expect_assert_failure( handle_stats_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_barrier_reply() tests. ********************************************************************************/ static void test_handle_barrier_reply() { buffer *buffer; buffer = create_barrier_reply( TRANSACTION_ID ); expect_memory( mock_barrier_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_barrier_reply_handler, transaction_id, TRANSACTION_ID ); expect_memory( mock_barrier_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA ); handle_barrier_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_barrier_reply_if_handler_is_not_registered() { buffer *buffer; buffer = create_barrier_reply( TRANSACTION_ID ); // FIXME handle_barrier_reply( DATAPATH_ID, buffer ); free_buffer( buffer ); } static void test_handle_barrier_reply_if_message_is_NULL() { set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA ); expect_assert_failure( handle_barrier_reply( DATAPATH_ID, NULL ) ); } static void test_handle_barrier_reply_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA ); expect_assert_failure( handle_barrier_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_queue_get_config_reply() tests. ********************************************************************************/ static void test_handle_queue_get_config_reply() { size_t queue_len; uint16_t port = 1; list_element *queues; buffer *buffer; struct ofp_packet_queue *queue[ 2 ]; struct ofp_queue_prop_header *prop_header; queue_len = offsetof( struct ofp_packet_queue, properties ) + sizeof( struct ofp_queue_prop_header ); queue[ 0 ] = xcalloc( 1, queue_len ); queue[ 1 ] = xcalloc( 1, queue_len ); queue[ 0 ]->queue_id = 1; queue[ 0 ]->len = 16; prop_header = queue[ 0 ]->properties; prop_header->property = OFPQT_NONE; prop_header->len = 8; queue[ 1 ]->queue_id = 2; queue[ 1 ]->len = 16; prop_header = queue[ 1 ]->properties; prop_header->property = OFPQT_NONE; prop_header->len = 8; create_list( &queues ); append_to_tail( &queues, queue[ 0 ] ); append_to_tail( &queues, queue[ 1 ] ); buffer = create_queue_get_config_reply( TRANSACTION_ID, port, queues ); expect_memory( mock_queue_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_queue_get_config_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_queue_get_config_reply_handler, port32, ( uint32_t ) port ); expect_memory( mock_queue_get_config_reply_handler, queue1, queue[ 0 ], queue_len ); expect_memory( mock_queue_get_config_reply_handler, queue2, queue[ 1 ], queue_len ); expect_memory( mock_queue_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA ); handle_queue_get_config_reply( DATAPATH_ID, buffer ); xfree( queue[ 0 ] ); xfree( queue[ 1 ] ); delete_list( queues ); free_buffer( buffer ); } static void test_handle_queue_get_config_reply_without_queues() { uint16_t port = 1; buffer *buffer; buffer = create_queue_get_config_reply( TRANSACTION_ID, port, NULL ); set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA ); expect_assert_failure( handle_queue_get_config_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } static void test_handle_queue_get_config_reply_if_handler_is_not_registered() { size_t queue_len; uint16_t port = 1; list_element *queues; buffer *buffer; struct ofp_packet_queue *queue[ 2 ]; struct ofp_queue_prop_header *prop_header; queue_len = offsetof( struct ofp_packet_queue, properties ) + sizeof( struct ofp_queue_prop_header ); queue[ 0 ] = xcalloc( 1, queue_len ); queue[ 1 ] = xcalloc( 1, queue_len ); queue[ 0 ]->queue_id = 1; queue[ 0 ]->len = 16; prop_header = queue[ 0 ]->properties; prop_header->property = OFPQT_NONE; prop_header->len = 8; queue[ 1 ]->queue_id = 2; queue[ 1 ]->len = 16; prop_header = queue[ 1 ]->properties; prop_header->property = OFPQT_NONE; prop_header->len = 8; create_list( &queues ); append_to_tail( &queues, queue[ 0 ] ); append_to_tail( &queues, queue[ 1 ] ); buffer = create_queue_get_config_reply( TRANSACTION_ID, port, queues ); // FIXME handle_queue_get_config_reply( DATAPATH_ID, buffer ); xfree( queue[ 0 ] ); xfree( queue[ 1 ] ); delete_list( queues ); free_buffer( buffer ); } static void test_handle_queue_get_config_reply_if_message_is_NULL() { set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA ); expect_assert_failure( handle_queue_get_config_reply( DATAPATH_ID, NULL ) ); } static void test_handle_queue_get_config_reply_if_message_length_is_zero() { buffer *buffer; buffer = alloc_buffer_with_length( 32 ); set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA ); expect_assert_failure( handle_queue_get_config_reply( DATAPATH_ID, buffer ) ); free_buffer( buffer ); } /******************************************************************************** * handle_list_switches_reply() tests. ********************************************************************************/ static void test_insert_dpid() { list_element *head; create_list( &head ); uint64_t alice = 0x1; uint64_t bob = 0x2; uint64_t carol = 0x3; insert_dpid( &head, &carol ); insert_dpid( &head, &alice ); insert_dpid( &head, &bob ); list_element *element = head; assert_true( element != NULL ); assert_true( element->data != NULL ); assert_true( alice == *( uint64_t * ) element->data ); element = element->next; assert_true( element != NULL ); assert_true( element->data != NULL ); assert_true( bob == *( uint64_t * ) element->data ); element = element->next; assert_true( element != NULL ); assert_true( element->data != NULL ); assert_true( carol == *( uint64_t * ) element->data ); element = element->next; assert_true( element == NULL ); delete_list( head ); } static void test_insert_dpid_if_head_is_NULL() { uint64_t dpid = 0x1; expect_assert_failure( insert_dpid( NULL, &dpid ) ); } static void test_insert_dpid_if_dpid_is_NULL() { list_element *head; create_list( &head ); expect_assert_failure( insert_dpid( &head, NULL ) ); delete_list( head ); } static void test_handle_list_switches_reply() { uint16_t message_type = 0; uint64_t alice = 0x1; uint64_t bob = 0x2; uint64_t carol = 0x3; uint64_t dpid[] = { htonll( bob ), htonll( carol ), htonll( alice ) }; size_t length = sizeof( dpid ); void *user_data = LIST_SWITCHES_REPLY_USER_DATA; expect_value( mock_handle_list_switches_reply, *dpid1, alice ); expect_value( mock_handle_list_switches_reply, *dpid2, bob ); expect_value( mock_handle_list_switches_reply, *dpid3, carol ); expect_value( mock_handle_list_switches_reply, user_data, LIST_SWITCHES_REPLY_USER_DATA ); set_list_switches_reply_handler( mock_handle_list_switches_reply ); handle_list_switches_reply( message_type, dpid, length, user_data ); } static void test_handle_list_switches_reply_if_data_is_NULL() { uint16_t message_type = 0; size_t length = 64; void *user_data = LIST_SWITCHES_REPLY_USER_DATA; set_list_switches_reply_handler( mock_handle_list_switches_reply ); expect_assert_failure( handle_list_switches_reply( message_type, NULL, length, user_data ) ); } static void test_handle_list_switches_reply_if_length_is_zero() { uint16_t message_type = 0; uint64_t dpid[] = { 0 }; void *user_data = LIST_SWITCHES_REPLY_USER_DATA; expect_value( mock_handle_list_switches_reply, user_data, LIST_SWITCHES_REPLY_USER_DATA ); set_list_switches_reply_handler( mock_handle_list_switches_reply ); handle_list_switches_reply( message_type, dpid, 0, user_data ); } /******************************************************************************** * handle_switch_events() tests. ********************************************************************************/ static void test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_CONNECTED() { buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); append_back_buffer( data, sizeof( openflow_service_header_t ) ); handle_switch_events( MESSENGER_OPENFLOW_CONNECTED, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" ) ); } static void test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED() { uint64_t *datapath_id; buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) ); *datapath_id = htonll( DATAPATH_ID ); expect_memory( mock_switch_disconnected_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_switch_disconnected_handler, user_data, SWITCH_DISCONNECTED_USER_DATA ); expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME ); will_return( mock_clear_send_queue, true ); set_switch_disconnected_handler( mock_switch_disconnected_handler, SWITCH_DISCONNECTED_USER_DATA ); handle_switch_events( MESSENGER_OPENFLOW_DISCONNECTED, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" ) ); } static void test_handle_switch_events_if_message_is_NULL() { expect_assert_failure( handle_switch_events( MESSENGER_OPENFLOW_READY, NULL, 1 ) ); } static void test_handle_switch_events_if_message_length_is_zero() { buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); expect_assert_failure( handle_switch_events( MESSENGER_OPENFLOW_READY, data->data, 0 ) ); free_buffer( data ); } static void test_handle_switch_events_if_message_length_is_too_big() { buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); expect_assert_failure( handle_switch_events( MESSENGER_OPENFLOW_READY, data->data, data->length + 1 ) ); free_buffer( data ); } static void test_handle_switch_events_if_unhandled_message_type() { buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); append_back_buffer( data, sizeof( openflow_service_header_t ) ); // FIXME handle_switch_events( MESSENGER_OPENFLOW_MESSAGE, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" ) ); } /******************************************************************************** * handle_openflow_message() tests. ********************************************************************************/ static void test_handle_openflow_message() { openflow_service_header_t messenger_header; stat_entry *stat; messenger_header.datapath_id = htonll( DATAPATH_ID ); messenger_header.service_name_length = 0; // error { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_error( TRANSACTION_ID, OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE, data ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_error_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_error_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_error_handler, type32, OFPET_HELLO_FAILED ); expect_value( mock_error_handler, code32, OFPHFC_INCOMPATIBLE ); expect_value( mock_error_handler, data->length, data->length ); expect_memory( mock_error_handler, data->data, data->data, data->length ); expect_memory( mock_error_handler, user_data, USER_DATA, USER_DATA_LEN ); set_error_handler( mock_error_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.error_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.error_receive_succeeded" ) ); } // vendor { buffer *buffer, *data; data = alloc_buffer_with_length( 16 ); append_back_buffer( data, 16 ); memset( data->data, 'a', 16 ); buffer = create_vendor( TRANSACTION_ID, VENDOR_ID, data ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_vendor_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_vendor_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_vendor_handler, vendor, VENDOR_ID ); expect_value( mock_vendor_handler, data->length, data->length ); expect_memory( mock_vendor_handler, data->data, data->data, data->length ); expect_memory( mock_vendor_handler, user_data, USER_DATA, USER_DATA_LEN ); set_vendor_handler( mock_vendor_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.vendor_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.vendor_receive_succeeded" ) ); } // features_reply { uint8_t n_tables = 2; uint32_t n_buffers = 1024; uint32_t capabilities; uint32_t actions; struct ofp_phy_port *phy_port[ 2 ]; buffer *buffer; list_element *ports; capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | OFPC_QUEUE_STATS | OFPC_ARP_MATCH_IP ); actions = ( ( 1 << OFPAT_OUTPUT ) | ( 1 << OFPAT_SET_VLAN_VID ) | ( 1 << OFPAT_SET_TP_SRC ) | ( 1 << OFPAT_SET_TP_DST ) ); phy_port[ 0 ] = xcalloc( 1, sizeof( struct ofp_phy_port ) ); phy_port[ 1 ] = xcalloc( 1, sizeof( struct ofp_phy_port ) ); phy_port[ 0 ]->port_no = 1; memcpy( phy_port[ 0 ]->hw_addr, MAC_ADDR_X, sizeof( phy_port[ 0 ]->hw_addr ) ); memset( phy_port[ 0 ]->name, '\0', OFP_MAX_PORT_NAME_LEN ); memcpy( phy_port[ 0 ]->name, PORT_NAME, strlen( PORT_NAME ) ); phy_port[ 0 ]->config = OFPPC_PORT_DOWN; phy_port[ 0 ]->state = OFPPS_LINK_DOWN; phy_port[ 0 ]->curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE ); phy_port[ 0 ]->advertised = PORT_FEATURES; phy_port[ 0 ]->supported = PORT_FEATURES; phy_port[ 0 ]->peer = PORT_FEATURES; memcpy( phy_port[ 1 ], phy_port [ 0 ], sizeof( struct ofp_phy_port ) ); phy_port[ 1 ]->port_no = 2; memcpy( phy_port[ 1 ]->hw_addr, MAC_ADDR_Y, sizeof( phy_port[ 1 ]->hw_addr ) ); create_list( &ports ); append_to_tail( &ports, phy_port[ 0 ] ); append_to_tail( &ports, phy_port[ 1 ] ); buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables, capabilities, actions, ports ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_features_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_features_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_features_reply_handler, n_buffers, n_buffers ); expect_value( mock_features_reply_handler, n_tables32, ( uint32_t ) n_tables ); expect_value( mock_features_reply_handler, capabilities, capabilities ); expect_value( mock_features_reply_handler, actions, actions ); expect_memory( mock_features_reply_handler, port1, ports->data, sizeof( struct ofp_phy_port ) ); expect_memory( mock_features_reply_handler, port2, ports->next->data, sizeof( struct ofp_phy_port ) ); expect_memory( mock_features_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_features_reply_handler( mock_features_reply_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.features_reply_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); xfree( phy_port[ 0 ] ); xfree( phy_port[ 1 ] ); delete_list( ports ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.features_reply_receive_succeeded" ) ); } // get_config_reply { uint16_t flags = OFPC_FRAG_NORMAL; uint16_t miss_send_len = 128; buffer *buffer; buffer = create_get_config_reply( TRANSACTION_ID, flags, miss_send_len ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_get_config_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_get_config_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_get_config_reply_handler, miss_send_len32, ( uint32_t ) miss_send_len ); expect_memory( mock_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.get_config_reply_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.get_config_reply_receive_succeeded" ) ); } // packet_in { uint8_t reason = OFPR_NO_MATCH; uint16_t total_len; uint16_t in_port = 1; uint32_t buffer_id = 0x01020304; buffer *buffer, *data; data = alloc_buffer_with_length( 64 ); append_back_buffer( data, 64 ); memset( data->data, 0x01, 64 ); total_len = ( uint16_t ) data->length; buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, in_port, reason, data ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); will_return( mock_parse_packet, true ); expect_memory( mock_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_packet_in_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_packet_in_handler, buffer_id, buffer_id ); expect_value( mock_packet_in_handler, total_len32, ( uint32_t ) total_len ); expect_value( mock_packet_in_handler, in_port32, ( uint32_t ) in_port ); expect_value( mock_packet_in_handler, reason32, ( uint32_t ) reason ); expect_value( mock_packet_in_handler, data->length, data->length ); expect_memory( mock_packet_in_handler, data->data, data->data, data->length ); expect_memory( mock_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN ); set_packet_in_handler( mock_packet_in_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.packet_in_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.packet_in_receive_succeeded" ) ); } // flow_removed { uint8_t reason = OFPRR_IDLE_TIMEOUT; uint16_t idle_timeout = 60; uint16_t priority = UINT16_MAX; uint32_t duration_sec = 180; uint32_t duration_nsec = 10000; uint64_t cookie = 0x0102030405060708ULL; uint64_t packet_count = 1000; uint64_t byte_count = 100000; buffer *buffer; buffer = create_flow_removed( TRANSACTION_ID, MATCH, cookie, priority, reason, duration_sec, duration_nsec, idle_timeout, packet_count, byte_count ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_flow_removed_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_flow_removed_handler, transaction_id, TRANSACTION_ID ); expect_memory( mock_flow_removed_handler, &match, &MATCH, sizeof( struct ofp_match ) ); expect_memory( mock_flow_removed_handler, &cookie, &cookie, sizeof( uint64_t ) ); expect_value( mock_flow_removed_handler, priority32, ( uint32_t ) priority ); expect_value( mock_flow_removed_handler, reason32, ( uint32_t ) reason ); expect_value( mock_flow_removed_handler, duration_sec, duration_sec ); expect_value( mock_flow_removed_handler, duration_nsec, duration_nsec ); expect_value( mock_flow_removed_handler, idle_timeout32, ( uint32_t ) idle_timeout ); expect_memory( mock_flow_removed_handler, &packet_count, &packet_count, sizeof( uint64_t ) ); expect_memory( mock_flow_removed_handler, &byte_count, &byte_count, sizeof( uint64_t ) ); expect_memory( mock_flow_removed_handler, user_data, USER_DATA, USER_DATA_LEN ); set_flow_removed_handler( mock_flow_removed_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.flow_removed_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.flow_removed_receive_succeeded" ) ); } // port_status { uint8_t reason = OFPPR_MODIFY; buffer *buffer; struct ofp_phy_port desc; desc.port_no = 1; memcpy( desc.hw_addr, MAC_ADDR_X, sizeof( desc.hw_addr ) ); memset( desc.name, '\0', OFP_MAX_PORT_NAME_LEN ); memcpy( desc.name, PORT_NAME, strlen( PORT_NAME ) ); desc.config = OFPPC_PORT_DOWN; desc.state = OFPPS_LINK_DOWN; desc.curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE ); desc.advertised = PORT_FEATURES; desc.supported = PORT_FEATURES; desc.peer = PORT_FEATURES; buffer = create_port_status( TRANSACTION_ID, reason, desc ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_port_status_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_port_status_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_port_status_handler, reason32, ( uint32_t ) reason ); expect_memory( mock_port_status_handler, &phy_port, &desc, sizeof( struct ofp_phy_port ) ); expect_memory( mock_port_status_handler, user_data, USER_DATA, USER_DATA_LEN ); set_port_status_handler( mock_port_status_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.port_status_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.port_status_receive_succeeded" ) ); } // stats_reply { char mfr_desc[ DESC_STR_LEN ]; char hw_desc[ DESC_STR_LEN ]; char sw_desc[ DESC_STR_LEN ]; char serial_num[ SERIAL_NUM_LEN ]; char dp_desc[ DESC_STR_LEN ]; uint16_t flags = 0; uint32_t body_len; buffer *buffer; struct ofp_stats_reply *stats_reply; memset( mfr_desc, '\0', DESC_STR_LEN ); memset( hw_desc, '\0', DESC_STR_LEN ); memset( sw_desc, '\0', DESC_STR_LEN ); memset( serial_num, '\0', SERIAL_NUM_LEN ); memset( dp_desc, '\0', DESC_STR_LEN ); sprintf( mfr_desc, "NEC Coporation" ); sprintf( hw_desc, "OpenFlow Switch Hardware" ); sprintf( sw_desc, "OpenFlow Switch Software" ); sprintf( serial_num, "123456" ); sprintf( dp_desc, "Datapath 0" ); buffer = create_desc_stats_reply( TRANSACTION_ID, flags, mfr_desc, hw_desc, sw_desc, serial_num, dp_desc ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); stats_reply = ( struct ofp_stats_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) ); body_len = ( uint32_t ) ( ntohs( stats_reply->header.length ) - offsetof( struct ofp_stats_reply, body ) ); expect_memory( mock_stats_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_stats_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_stats_reply_handler, type32, OFPST_DESC ); expect_value( mock_stats_reply_handler, flags32, ( uint32_t ) flags ); expect_value( mock_stats_reply_handler, data->length, body_len ); expect_memory( mock_stats_reply_handler, data->data, stats_reply->body, body_len ); expect_memory( mock_stats_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_stats_reply_handler( mock_stats_reply_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.stats_reply_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.stats_reply_receive_succeeded" ) ); } // barrier_reply { buffer *buffer; buffer = create_barrier_reply( TRANSACTION_ID ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_barrier_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_barrier_reply_handler, transaction_id, TRANSACTION_ID ); expect_memory( mock_barrier_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" ) ); } // queue_get_config_reply { size_t queue_len; uint16_t port = 1; list_element *queues; buffer *buffer; struct ofp_packet_queue *queue[ 2 ]; struct ofp_queue_prop_header *prop_header; queue_len = offsetof( struct ofp_packet_queue, properties ) + sizeof( struct ofp_queue_prop_header ); queue[ 0 ] = xcalloc( 1, queue_len ); queue[ 1 ] = xcalloc( 1, queue_len ); queue[ 0 ]->queue_id = 1; queue[ 0 ]->len = 16; prop_header = queue[ 0 ]->properties; prop_header->property = OFPQT_NONE; prop_header->len = 8; queue[ 1 ]->queue_id = 2; queue[ 1 ]->len = 16; prop_header = queue[ 1 ]->properties; prop_header->property = OFPQT_NONE; prop_header->len = 8; create_list( &queues ); append_to_tail( &queues, queue[ 0 ] ); append_to_tail( &queues, queue[ 1 ] ); buffer = create_queue_get_config_reply( TRANSACTION_ID, port, queues ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); expect_memory( mock_queue_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_queue_get_config_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_queue_get_config_reply_handler, port32, ( uint32_t ) port ); expect_memory( mock_queue_get_config_reply_handler, queue1, queue[ 0 ], queue_len ); expect_memory( mock_queue_get_config_reply_handler, queue2, queue[ 1 ], queue_len ); expect_memory( mock_queue_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN ); set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA ); handle_openflow_message( buffer->data, buffer->length ); stat = lookup_hash_entry( stats, "openflow_application_interface.queue_get_config_reply_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); xfree( queue[ 0 ] ); xfree( queue[ 1 ] ); delete_list( queues ); free_buffer( buffer ); xfree( delete_hash_entry( stats, "openflow_application_interface.queue_get_config_reply_receive_succeeded" ) ); } // unhandled message { buffer *buffer; buffer = create_hello( TRANSACTION_ID ); struct ofp_header *header = buffer->data; header->type = OFPT_QUEUE_GET_CONFIG_REPLY + 1; append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); // FIXME handle_openflow_message( buffer->data, buffer->length ); free_buffer( buffer ); } } static void test_handle_openflow_message_with_malformed_message() { buffer *buffer; openflow_service_header_t messenger_header; struct ofp_header *header; messenger_header.datapath_id = htonll( DATAPATH_ID ); messenger_header.service_name_length = 0; buffer = create_hello( TRANSACTION_ID ); header = buffer->data; header->length = htons( UINT16_MAX ); append_front_buffer( buffer, sizeof( openflow_service_header_t ) ); memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) ); handle_openflow_message( buffer->data, buffer->length ); free_buffer( buffer ); } static void test_handle_openflow_message_if_message_is_NULL() { expect_assert_failure( handle_openflow_message( NULL, 1 ) ); } static void test_handle_openflow_message_if_message_length_is_zero() { buffer *data; data = alloc_buffer_with_length( 32 ); expect_assert_failure( handle_openflow_message( data, 0 ) ); free_buffer( data ); } static void test_handle_openflow_message_if_unhandled_message_type() { buffer *data; data = alloc_buffer_with_length( 32 ); append_back_buffer( data, 32 ); // FIXME handle_openflow_message( data, data->length ); free_buffer( data ); } /******************************************************************************** * handle_message() tests. ********************************************************************************/ static void test_handle_message_if_type_is_MESSENGER_OPENFLOW_MESSAGE() { buffer *data; openflow_service_header_t *header; data = create_barrier_reply( TRANSACTION_ID ); assert_true( data != NULL ); append_front_buffer( data, sizeof( openflow_service_header_t ) ); header = data->data; header->datapath_id = htonll( DATAPATH_ID ); header->service_name_length = 0; expect_memory( mock_barrier_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_barrier_reply_handler, transaction_id, TRANSACTION_ID ); expect_value( mock_barrier_reply_handler, user_data, BARRIER_REPLY_USER_DATA ); set_barrier_reply_handler( mock_barrier_reply_handler, BARRIER_REPLY_USER_DATA ); handle_message( MESSENGER_OPENFLOW_MESSAGE, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" ) ); } static void test_handle_message_if_type_is_MESSENGER_OPENFLOW_CONNECTED() { buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); append_back_buffer( data, sizeof( openflow_service_header_t ) ); handle_message( MESSENGER_OPENFLOW_CONNECTED, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" ) ); } static void test_handle_message_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED() { uint64_t *datapath_id; buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) ); *datapath_id = htonll( DATAPATH_ID ); expect_memory( mock_switch_disconnected_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) ); expect_value( mock_switch_disconnected_handler, user_data, SWITCH_DISCONNECTED_USER_DATA ); expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME ); will_return( mock_clear_send_queue, true ); set_switch_disconnected_handler( mock_switch_disconnected_handler, SWITCH_DISCONNECTED_USER_DATA ); handle_message( MESSENGER_OPENFLOW_DISCONNECTED, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" ) ); } static void test_handle_message_if_message_is_NULL() { expect_assert_failure( handle_message( MESSENGER_OPENFLOW_MESSAGE, NULL, 1 ) ); } static void test_handle_message_if_message_length_is_zero() { buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); expect_assert_failure( handle_message( MESSENGER_OPENFLOW_MESSAGE, data->data, 0 ) ); free_buffer( data ); } static void test_handle_message_if_unhandled_message_type() { buffer *data; data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) ); append_back_buffer( data, sizeof( openflow_service_header_t ) ); // FIXME handle_message( MESSENGER_OPENFLOW_DISCONNECTED + 1, data->data, data->length ); stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" ); assert_int_equal( ( int ) stat->value, 1 ); free_buffer( data ); xfree( delete_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" ) ); } /******************************************************************************** * delete_openflow_messages() tests. ********************************************************************************/ static void test_delete_openflow_messages() { expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME ); will_return( mock_clear_send_queue, true ); assert_true( delete_openflow_messages( DATAPATH_ID ) ); } static void test_delete_openflow_messages_if_clear_send_queue_fails() { expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME ); will_return( mock_clear_send_queue, false ); assert_false( delete_openflow_messages( DATAPATH_ID ) ); } /******************************************************************************** * Run tests. ********************************************************************************/ int main() { const UnitTest tests[] = { // initialization and finalization tests. unit_test_setup_teardown( test_init_openflow_application_interface_with_valid_custom_service_name, cleanup, cleanup ), unit_test_setup_teardown( test_init_openflow_application_interface_with_too_long_custom_service_name, cleanup, cleanup ), unit_test_setup_teardown( test_init_openflow_application_interface_if_already_initialized, init, cleanup ), unit_test_setup_teardown( test_finalize_openflow_application_interface, init, cleanup ), unit_test_setup_teardown( test_finalize_openflow_application_interface_if_not_initialized, cleanup, cleanup ), unit_test_setup_teardown( test_set_openflow_event_handlers, init, cleanup ), // switch ready handler tests. unit_test_setup_teardown( test_set_switch_ready_handler, init, cleanup ), unit_test_setup_teardown( test_set_simple_switch_ready_handler, init, cleanup ), unit_test_setup_teardown( test_set_switch_ready_handler_should_die_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_switch_ready, init, cleanup ), unit_test_setup_teardown( test_handle_switch_ready_with_simple_handler, init, cleanup ), // switch disconnected handler tests. unit_test_setup_teardown( test_set_switch_disconnected_handler, init, cleanup ), unit_test_setup_teardown( test_set_switch_disconnected_handler_if_handler_is_NULL, init, cleanup ), // error handler tests. unit_test_setup_teardown( test_set_error_handler, init, cleanup ), unit_test_setup_teardown( test_set_error_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_error, init, cleanup ), unit_test_setup_teardown( test_handle_error_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_error_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_error_if_message_length_is_zero, init, cleanup ), // echo_reply handler tests. unit_test_setup_teardown( test_set_echo_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_echo_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_echo_reply, init, cleanup ), unit_test_setup_teardown( test_handle_echo_reply_without_data, init, cleanup ), unit_test_setup_teardown( test_handle_echo_reply_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_echo_reply_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_echo_reply_if_message_length_is_zero, init, cleanup ), // vendor handler tests. unit_test_setup_teardown( test_set_vendor_handler, init, cleanup ), unit_test_setup_teardown( test_set_vendor_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_vendor, init, cleanup ), unit_test_setup_teardown( test_handle_vendor_without_data, init, cleanup ), unit_test_setup_teardown( test_handle_vendor_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_vendor_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_vendor_if_message_length_is_zero, init, cleanup ), // features reply handler tests. unit_test_setup_teardown( test_set_features_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_features_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_features_reply, init, cleanup ), unit_test_setup_teardown( test_handle_features_reply_without_phy_port, init, cleanup ), unit_test_setup_teardown( test_handle_features_reply_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_features_reply_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_features_reply_if_message_length_is_zero, init, cleanup ), // get config reply handler tests. unit_test_setup_teardown( test_set_get_config_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_get_config_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_get_config_reply, init, cleanup ), unit_test_setup_teardown( test_handle_get_config_reply_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_get_config_reply_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_get_config_reply_if_message_length_is_zero, init, cleanup ), // flow removed handler tests. unit_test_setup_teardown( test_set_flow_removed_handler, init, cleanup ), unit_test_setup_teardown( test_set_flow_removed_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_flow_removed, init, cleanup ), unit_test_setup_teardown( test_handle_flow_removed_with_simple_handler, init, cleanup ), unit_test_setup_teardown( test_set_simple_flow_removed_handler, init, cleanup ), unit_test_setup_teardown( test_handle_flow_removed_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_flow_removed_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_flow_removed_if_message_length_is_zero, init, cleanup ), // port status handler tests. unit_test_setup_teardown( test_set_port_status_handler, init, cleanup ), unit_test_setup_teardown( test_set_port_status_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_port_status, init, cleanup ), unit_test_setup_teardown( test_handle_port_status_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_port_status_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_port_status_if_message_length_is_zero, init, cleanup ), // stats reply handler tests. unit_test_setup_teardown( test_set_stats_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_stats_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_DESC, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_FLOW, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_AGGREGATE, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_TABLE, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_PORT, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_QUEUE, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_type_is_OFPST_VENDOR, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_with_undefined_type, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_stats_reply_if_message_length_is_zero, init, cleanup ), // barrier reply handler tests. unit_test_setup_teardown( test_set_barrier_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_barrier_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_barrier_reply, init, cleanup ), unit_test_setup_teardown( test_handle_barrier_reply_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_barrier_reply_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_barrier_reply_if_message_length_is_zero, init, cleanup ), // queue get config reply handler tests. unit_test_setup_teardown( test_set_queue_get_config_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_queue_get_config_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_queue_get_config_reply, init, cleanup ), unit_test_setup_teardown( test_handle_queue_get_config_reply_without_queues, init, cleanup ), unit_test_setup_teardown( test_handle_queue_get_config_reply_if_handler_is_not_registered, init, cleanup ), unit_test_setup_teardown( test_handle_queue_get_config_reply_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_queue_get_config_reply_if_message_length_is_zero, init, cleanup ), // list switches reply handler tests. unit_test_setup_teardown( test_set_list_switches_reply_handler, init, cleanup ), unit_test_setup_teardown( test_set_list_switches_reply_handler_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_list_switches_reply, init, cleanup ), unit_test_setup_teardown( test_handle_list_switches_reply_if_data_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_list_switches_reply_if_length_is_zero, init, cleanup ), // packet-in handler tests. unit_test_setup_teardown( test_set_packet_in_handler, init, cleanup ), unit_test_setup_teardown( test_set_simple_packet_in_handler, init, cleanup ), unit_test_setup_teardown( test_set_packet_in_handler_should_die_if_handler_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in_with_simple_handler, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in_with_malformed_packet, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in_without_data, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in_without_handler, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in_should_die_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_packet_in_should_die_if_message_length_is_zero, init, cleanup ), // miscellaneous tests. unit_test_setup_teardown( test_insert_dpid, init, cleanup ), unit_test_setup_teardown( test_insert_dpid_if_head_is_NULL, init, cleanup ), unit_test_setup_teardown( test_insert_dpid_if_dpid_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_CONNECTED, init, cleanup ), unit_test_setup_teardown( test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED, init, cleanup ), unit_test_setup_teardown( test_handle_switch_events_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_switch_events_if_message_length_is_zero, init, cleanup ), unit_test_setup_teardown( test_handle_switch_events_if_message_length_is_too_big, init, cleanup ), unit_test_setup_teardown( test_handle_switch_events_if_unhandled_message_type, init, cleanup ), unit_test_setup_teardown( test_handle_openflow_message, init, cleanup ), unit_test_setup_teardown( test_handle_openflow_message_with_malformed_message, init, cleanup ), unit_test_setup_teardown( test_handle_openflow_message_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_openflow_message_if_message_length_is_zero, init, cleanup ), unit_test_setup_teardown( test_handle_openflow_message_if_unhandled_message_type, init, cleanup ), unit_test_setup_teardown( test_handle_message_if_type_is_MESSENGER_OPENFLOW_MESSAGE, init, cleanup ), unit_test_setup_teardown( test_handle_message_if_type_is_MESSENGER_OPENFLOW_CONNECTED, init, cleanup ), unit_test_setup_teardown( test_handle_message_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED, init, cleanup ), unit_test_setup_teardown( test_handle_message_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_handle_message_if_message_length_is_zero, init, cleanup ), unit_test_setup_teardown( test_handle_message_if_unhandled_message_type, init, cleanup ), // send_openflow_message() tests. unit_test_setup_teardown( test_send_openflow_message, init, cleanup ), unit_test_setup_teardown( test_send_openflow_message_if_message_is_NULL, init, cleanup ), unit_test_setup_teardown( test_send_openflow_message_if_message_length_is_zero, init, cleanup ), // delete_openflow_messages() tests. unit_test_setup_teardown( test_delete_openflow_messages, init, cleanup ), unit_test_setup_teardown( test_delete_openflow_messages_if_clear_send_queue_fails, init, cleanup ), }; return run_tests( tests ); } /* * Local variables: * c-basic-offset: 2 * indent-tabs-mode: nil * End: */