/* * Sample OpenFlow event dumper. * * Author: Yasunobu Chiba * * Copyright (C) 2008-2012 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 "trema.h" #define dump info void usage() { printf( "OpenFlow Event Dumper.\n" "Usage: %s [OPTION]...\n" "\n" " -n, --name=SERVICE_NAME service name\n" " -d, --daemonize run in the background\n" " -l, --logging_level=LEVEL set logging level\n" " -g, --syslog output log messages to syslog\n" " -f, --logging_facility=FACILITY set syslog facility\n" " -h, --help display this help and exit\n" , get_executable_name() ); } static void dump_phy_port( const struct ofp_phy_port *phy_port ) { dump( "port_no: %u", phy_port->port_no ); dump( " hw_addr: %02x:%02x:%02x:%02x:%02x:%02x", phy_port->hw_addr[ 0 ], phy_port->hw_addr[ 1 ], phy_port->hw_addr[ 2 ], phy_port->hw_addr[ 3 ], phy_port->hw_addr[ 4 ], phy_port->hw_addr[ 5 ] ); dump( " name: %s", phy_port->name ); dump( " config: %#x", phy_port->config ); dump( " state: %#x", phy_port->state ); dump( " curr: %#x", phy_port->curr ); dump( " advertised: %#x", phy_port->advertised ); dump( " supported: %#x", phy_port->supported ); dump( " peer: %#x", phy_port->peer ); } static void dump_packet_queue( const struct ofp_packet_queue *packet_queue ) { uint16_t properties_length; struct ofp_queue_prop_header *prop_header, *properties_head; struct ofp_queue_prop_min_rate *prop_min_rate; dump( "queue_id: %#x", packet_queue->queue_id ); dump( " len: %u", packet_queue->len ); dump( " properties:" ); properties_length = ( uint16_t ) ( packet_queue->len - offsetof( struct ofp_packet_queue, properties ) ); properties_head = ( struct ofp_queue_prop_header * ) xmalloc( properties_length ); memcpy( properties_head, packet_queue->properties, properties_length ); prop_header = properties_head; while ( properties_length > 0 ) { dump( " property: %#x", prop_header->property ); dump( " len: %#x", prop_header->len ); if ( prop_header->property == OFPQT_MIN_RATE ) { prop_min_rate = ( struct ofp_queue_prop_min_rate * ) prop_header; dump( " rate: %u", prop_min_rate->rate ); } properties_length = ( uint16_t ) ( properties_length - prop_header->len ); prop_header = ( struct ofp_queue_prop_header * ) ( ( char * ) prop_header + prop_header->len ); } xfree( properties_head ); } static void handle_switch_ready( uint64_t datapath_id, void *user_data ) { UNUSED( user_data ); dump( "[switch_ready]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); } static void handle_switch_disconnected( uint64_t datapath_id, void *user_data ) { UNUSED( user_data ); dump( "[switch_disconnected]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); } static void handle_error( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t code, const buffer *data, void *user_data ) { UNUSED( user_data ); dump( "[error]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "type: %#x", type ); dump( "code: %#x", code ); dump( "data:" ); dump_buffer( data, dump ); } static void handle_vendor( uint64_t datapath_id, uint32_t transaction_id, uint32_t vendor, const buffer *data, void *user_data ) { UNUSED( user_data ); dump( "[vendor]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "vendor: %#x", vendor ); dump( "data:" ); dump_buffer( data, dump ); } static void handle_features_reply( 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 ) { UNUSED( user_data ); list_element *element, *phy_ports_head; struct ofp_phy_port *phy_port; dump( "[features_reply]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "n_buffers: %u", n_buffers ); dump( "n_tables: %u", n_tables ); dump( "capabilities: %#x", capabilities ); dump( "actions: %#x", actions ); phy_ports_head = ( list_element * ) xmalloc( sizeof( list_element ) ); memcpy( phy_ports_head, phy_ports, sizeof( list_element ) ); element = phy_ports_head; while ( element != NULL ) { phy_port = ( struct ofp_phy_port * ) element->data; dump_phy_port( phy_port ); element = element->next; } xfree( phy_ports_head ); } static void handle_get_config_reply( uint64_t datapath_id, uint32_t transaction_id, uint16_t flags, uint16_t miss_send_len, void *user_data ) { UNUSED( user_data ); dump( "[get_config_reply]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "flags: %#x", flags ); dump( "miss_send_len: %u", miss_send_len ); } static void handle_packet_in( 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 ) { UNUSED( user_data ); dump( "[packet_in]" ); dump( " datapath_id: %#" PRIx64, datapath_id ); dump( " transaction_id: %#x", transaction_id ); dump( " buffer_id: %#x", buffer_id ); dump( " total_len: %u", total_len ); dump( " in_port: %u", in_port ); dump( " reason: %#x", reason ); dump( " data:" ); dump_buffer( data, dump ); } static void handle_flow_removed( uint64_t datapath_id, flow_removed message ) { dump( "[flow_removed]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", message.transaction_id ); dump( "match:" ); dump( " wildcards: %#x", message.match.wildcards ); dump( " in_port: %u", message.match.in_port ); dump( " dl_src: %02x:%02x:%02x:%02x:%02x:%02x", message.match.dl_src[ 0 ], message.match.dl_src[ 1 ], message.match.dl_src[ 2 ], message.match.dl_src[ 3 ], message.match.dl_src[ 4 ], message.match.dl_src[ 5 ] ); dump( " dl_dst: %02x:%02x:%02x:%02x:%02x:%02x", message.match.dl_dst[ 0 ], message.match.dl_dst[ 1 ], message.match.dl_dst[ 2 ], message.match.dl_dst[ 3 ], message.match.dl_dst[ 4 ], message.match.dl_dst[ 5 ] ); dump( " dl_vlan: %u", message.match.dl_vlan ); dump( " dl_vlan_pcp: %u", message.match.dl_vlan_pcp ); dump( " dl_type: %#x", message.match.dl_type ); dump( " nw_tos: %u", message.match.nw_tos ); dump( " nw_proto: %#x", message.match.nw_proto ); dump( " nw_src: %#x", message.match.nw_src ); dump( " nw_dst: %#x", message.match.nw_dst ); dump( " tp_src: %u", message.match.tp_src ); dump( " tp_dst: %u", message.match.tp_dst ); dump( "cookie: %#" PRIx64, message.cookie ); dump( "priority: %u", message.priority ); dump( "reason: %#x", message.reason ); dump( "duration_sec: %u", message.duration_sec ); dump( "duration_nsec: %u", message.duration_nsec ); dump( "idle_timeout: %u", message.idle_timeout ); dump( "packet_count: %" PRIu64, message.packet_count ); dump( "byte_count: %" PRIu64, message.byte_count ); } static void handle_port_status( uint64_t datapath_id, uint32_t transaction_id, uint8_t reason, struct ofp_phy_port phy_port, void *user_data ) { UNUSED( user_data ); dump( "[port_status]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "reason: %#x", reason ); dump( "phy_port:" ); dump_phy_port( &phy_port ); } static void handle_stats_reply( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t flags, const buffer *data, void *user_data ) { UNUSED( user_data ); dump( "[stats_reply]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "type: %#x", type ); dump( "flags: %#x", flags ); dump( "data:" ); dump_buffer( data, dump ); } static void handle_barrier_reply( uint64_t datapath_id, uint32_t transaction_id, void *user_data ) { UNUSED( user_data ); dump( "[barrier_reply]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); } static void handle_queue_get_config_reply( uint64_t datapath_id, uint32_t transaction_id, uint16_t port, const list_element *queues, void *user_data ) { UNUSED( user_data ); list_element *queues_head, *element; struct ofp_packet_queue *packet_queue; dump( "[queue_get_config_reply]" ); dump( "datapath_id: %#" PRIx64, datapath_id ); dump( "transaction_id: %#x", transaction_id ); dump( "port: %u", port ); dump( "queues:" ); queues_head = ( list_element * ) xmalloc( sizeof( list_element ) ); memcpy( queues_head, queues, sizeof( list_element ) ); element = queues_head; while ( element != NULL ) { packet_queue = ( struct ofp_packet_queue * ) element->data; dump_packet_queue( packet_queue ); element = element->next; } xfree( queues_head ); } int main( int argc, char *argv[] ) { // Initialize the Trema world init_trema( &argc, &argv ); // Set event handlers set_switch_ready_handler( handle_switch_ready, NULL ); set_switch_disconnected_handler( handle_switch_disconnected, NULL ); set_error_handler( handle_error, NULL ); set_vendor_handler( handle_vendor, NULL ); set_features_reply_handler( handle_features_reply, NULL ); set_get_config_reply_handler( handle_get_config_reply, NULL ); set_packet_in_handler( handle_packet_in, NULL ); set_flow_removed_handler( handle_flow_removed, NULL ); set_port_status_handler( handle_port_status, NULL ); set_stats_reply_handler( handle_stats_reply, NULL ); set_barrier_reply_handler( handle_barrier_reply, NULL ); set_queue_get_config_reply_handler( handle_queue_get_config_reply, NULL ); // Main loop start_trema(); return 0; } /* * Local variables: * c-basic-offset: 2 * indent-tabs-mode: nil * End: */