static void handle_flow_mod_mod( const uint32_t transaction_id, const uint64_t cookie, const uint64_t cookie_mask, const uint8_t table_id, const uint16_t idle_timeout, const uint16_t hard_timeout, const uint16_t priority, const uint32_t buffer_id, const uint16_t flags, const oxm_matches *oxm, const openflow_instructions *instructions, const bool strict, struct protocol *protocol ) { match *match = create_match( ); if ( oxm != NULL && oxm->n_matches > 0 ) { for ( list_element *e = oxm->list; e != NULL; e = e->next ) { oxm_match_header *hdr = e->data; assign_match( match, hdr ); } } instruction_set *ins_set = create_instruction_set(); if ( instructions != NULL ) { OFDPE ret = assign_instructions( ins_set, instructions->list ); if ( ret != OFDPE_SUCCESS ) { send_error_message( transaction_id, OFPET_FLOW_MOD_FAILED, OFPBIC_UNSUP_INST ); delete_instruction_set( ins_set ); delete_match( match ); return; } } OFDPE ret = update_or_add_flow_entry( table_id, match, cookie, cookie_mask, priority, idle_timeout, hard_timeout, flags, strict, ins_set ); delete_instruction_set( ins_set ); delete_match( match ); if ( ret != OFDPE_SUCCESS ) { uint16_t type = OFPET_FLOW_MOD_FAILED; uint16_t code = OFPFMFC_UNKNOWN; get_ofp_error( ret, &type, &code ); send_error_message( transaction_id, type, code ); return; } if ( buffer_id != OFP_NO_BUFFER ) { action_list *actions = create_action_list(); action *action = create_action_output( OFPP_TABLE, UINT16_MAX ); append_action( actions, action ); ret = execute_packet_out( buffer_id, 0, actions, NULL ); delete_action_list( actions ); if ( ret != OFDPE_SUCCESS ) { uint16_t type = OFPET_FLOW_MOD_FAILED; uint16_t code = OFPFMFC_UNKNOWN; get_ofp_error( ret, &type, &code ); send_error_message( transaction_id, type, code ); return; } wakeup_datapath( protocol ); } }
static flow_stats * retrieve_flow_stats( uint32_t *nr_stats, const uint8_t table_id, const uint32_t out_port, const uint32_t out_group, const uint64_t cookie, const uint64_t cookie_mask, const struct ofp_match *ofp_match ) { match *flow_match = create_match(); size_t match_len = 0; if ( ofp_match != NULL ) { match_len = ofp_match->length - offsetof( struct ofp_match, oxm_fields ); // translate the ofp_match to datapath match. const oxm_match_header *hdr = ( const oxm_match_header * ) ofp_match->oxm_fields; while ( match_len > 0 ) { assign_match( flow_match, hdr ); match_len -= ( sizeof( *hdr ) + OXM_LENGTH( *hdr ) ); if ( match_len > 0 ) { hdr = ( const oxm_match_header * ) ( ( const char * ) hdr + sizeof( *hdr ) + OXM_LENGTH( *hdr ) ); } } }
static void handle_flow_mod_delete( const uint32_t transaction_id, const uint64_t cookie, const uint64_t cookie_mask, const uint8_t table_id, const uint16_t idle_timeout, const uint16_t hard_timeout, const uint16_t priority, const uint32_t buffer_id, const uint32_t out_port, const uint32_t out_group, const uint16_t flags, const oxm_matches *oxm_match, const openflow_instructions *instructions, const bool strict ) { UNUSED( idle_timeout ); UNUSED( hard_timeout ); UNUSED( priority ); UNUSED( buffer_id ); UNUSED( flags ); UNUSED( instructions ); match *match = create_match(); if ( oxm_match != NULL && oxm_match->n_matches > 0 ) { for ( list_element *e = oxm_match->list; e != NULL; e = e->next ) { oxm_match_header *hdr = e->data; assign_match( match, hdr ); } } OFDPE ret = OFDPE_FAILED; if ( strict ) { ret = delete_flow_entry_strict( table_id, match, cookie, cookie_mask, priority, out_port, out_group ); } else { ret = delete_flow_entries( table_id, match, cookie, cookie_mask, out_port, out_group ); } if ( ret != OFDPE_SUCCESS ) { uint16_t type = OFPET_FLOW_MOD_FAILED; uint16_t code = OFPFMFC_UNKNOWN; get_ofp_error( ret, &type, &code ); send_error_message( transaction_id, type, code ); } delete_match( match ); }
static void handle_flow_mod_add( const uint32_t transaction_id, const uint64_t cookie, const uint64_t cookie_mask, const uint8_t table_id, const uint16_t idle_timeout, const uint16_t hard_timeout, const uint16_t priority, const uint32_t buffer_id, const uint16_t flags, const oxm_matches *oxm, const openflow_instructions *instructions, struct protocol *protocol ) { UNUSED( cookie_mask ); /* * currently if flags set OFPFF_SEND_FLOW_REM and OFPFF_RESET_COUNTS are the only allowed value. */ if ( ( flags & ~( OFPFF_SEND_FLOW_REM | OFPFF_RESET_COUNTS ) ) != 0 ) { send_error_message( transaction_id, OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_FLAGS ); return; } /* * The use of OFPTT_ALL is only valid for delete requests. */ if ( table_id == OFPTT_ALL ) { send_error_message( transaction_id, OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_TABLE_ID ); return; } /* * If no buffered packet is associated with a flow mod it must be set * to OFP_NO_BUFFER otherwise it must be equal to the buffer_id sent to * controller by a packet-in message. */ match *match = create_match(); if ( oxm != NULL && oxm->n_matches > 0 ) { #ifdef DEBUG char oxm_str[ 2048 ]; match_to_string( oxm, oxm_str, sizeof( oxm_str ) ); printf( "%s\n", oxm_str ); #endif for ( list_element *e = oxm->list; e != NULL; e = e->next ) { oxm_match_header *hdr = e->data; assign_match( match, hdr ); } } instruction_set *instruction_set = create_instruction_set(); if ( instructions != NULL ) { OFDPE ret = assign_instructions( instruction_set, instructions->list ); if ( ret != OFDPE_SUCCESS ) { send_error_message( transaction_id, OFPET_FLOW_MOD_FAILED, OFPBIC_UNSUP_INST ); delete_instruction_set( instruction_set ); delete_match( match ); return; } } /* * When a flow entry is inserted in a table, its flags field is set with the * values from the message. * When a flow entry is inserted in a table, its idle_timeout and * hard_timeout fields are set with the values from the message. * When a flow entry is inserted in a table through an OFPFC_ADD message, * its cookie field is set to the provided value */ flow_entry *new_entry = alloc_flow_entry( match, instruction_set, priority, idle_timeout, hard_timeout, flags, cookie ); if ( new_entry == NULL ) { /* * TODO we should send a more appropriate error once we worked out the * datapath errors. */ delete_instruction_set( instruction_set ); delete_match( match ); send_error_message( transaction_id, OFPET_FLOW_MOD_FAILED, OFPFMFC_UNKNOWN ); return; } OFDPE ret = add_flow_entry( table_id, new_entry, flags ); if ( ret != OFDPE_SUCCESS ) { error( "Failed to add a flow entry ( ret = %d ).", ret ); delete_instruction_set( instruction_set ); delete_match( match ); uint16_t type = OFPET_FLOW_MOD_FAILED; uint16_t code = OFPFMFC_UNKNOWN; get_ofp_error( ret, &type, &code ); send_error_message( transaction_id, type, code ); return; } if ( buffer_id != OFP_NO_BUFFER ) { action_list *actions = create_action_list(); action *action = create_action_output( OFPP_TABLE, UINT16_MAX ); append_action( actions, action ); ret = execute_packet_out( buffer_id, 0, actions, NULL ); delete_action_list( actions ); if ( ret != OFDPE_SUCCESS ) { uint16_t type = OFPET_FLOW_MOD_FAILED; uint16_t code = OFPFMFC_UNKNOWN; get_ofp_error( ret, &type, &code ); send_error_message( transaction_id, type, code ); return; } wakeup_datapath( protocol ); } }
static char * parse_dump_flows( char *cmd, const uint64_t own_datapath_id ) { if ( prefixcmp( cmd, "dump_flows" ) ) { return NULL; } char *opt = strchr ( cmd, ' ' ); assert( opt ); uint64_t datapath_val; uint32_t in_port_val; uint16_t eth_type_val; uint8_t ip_proto_val; uint64_t metadata_val[ 2 ]; uint16_t udp_src_val; uint16_t udp_dst_val; uint8_t table_id_val; uint32_t out_port_val; uint32_t out_group_val; uint64_t cookie_val[ 2 ]; struct option opts[] = { OPT_UINT64( "--datapath_id", "datapath_id:", OPT_NO_MASK, &datapath_val ), OPT_UINT32( "--in_port", "in_port:", OPT_NO_MASK, &in_port_val ), OPT_UINT16( "--eth_type", "eth_type:", OPT_NO_MASK, ð_type_val ), OPT_UINT8( "--ip_proto", "ip_proto:", OPT_NO_MASK, &ip_proto_val ), OPT_UINT64( "--metadata", "metadata:", OPT_HAS_MASK, &metadata_val ), OPT_UINT16( "--udp_src", "udp_src:", OPT_NO_MASK, &udp_src_val ), OPT_UINT16( "--udp_dst", "udp_dst:", OPT_NO_MASK, &udp_dst_val ), OPT_UINT8( "--table_id", "table_id:", OPT_NO_MASK, &table_id_val ), OPT_UINT64( "--cookie", "cookie:", OPT_HAS_MASK, &cookie_val ), OPT_UINT32( "--out_port", "out_port:", OPT_NO_MASK, &out_port_val ), OPT_UINT32( "--out_group", "out_group:", OPT_NO_MASK, &out_group_val ), OPT_END() }; char *saveptr; const char *sep = " "; for ( opt = strtok_r( opt, sep, &saveptr ); opt; opt = strtok_r( NULL, sep, &saveptr ) ) { parse_option( opt, opts ); if ( *( uint64_t * ) opts[ 0 ].value != own_datapath_id ) { return NULL; } } match *match = create_match(); parse_match( match, opts ); flow_stats *stats = NULL; uint32_t nr_stats; OFDPE ret = get_flow_stats( ( uint8_t ) table_id_val, match, cookie_val[ 0 ], cookie_val[ 1 ], out_port_val, out_group_val, &stats, &nr_stats ); if ( ret != OFDPE_SUCCESS ) { error( "Failed to retrieve flow stats from datapath ( ret = %d ).", ret ); } delete_match( match ); char *reply_buf = xmalloc( PATH_MAX + 1 ); reply_buf[ 0 ] = '\0'; size_t used = 0; int left; const char *term = ","; const char *orig = "{ \"dump_flows\": ["; if ( stats != NULL && nr_stats ) { for ( uint32_t i = 0; i < nr_stats; i++ ) { if ( i != 0 ) { orig = ""; } if ( i == nr_stats - 1 ) { term = "]}"; } left = snprintf( reply_buf + used, PATH_MAX - used, "%s {" DUMP_FLOW_FIELDS "} %s", orig, stats->table_id, stats->duration_sec, stats->priority, stats->idle_timeout, stats->hard_timeout, stats->flags, stats->cookie, stats->packet_count, stats->byte_count, term ); used = ( size_t ) left - used; stats++; } } return reply_buf; }