trema/trema-edge

View on GitHub
unittests/switch/switch/stats-helper-test.c

Summary

Maintainability
Test Coverage
/*
 * 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 <stdio.h>
#include <string.h>
#include "cmockery_trema.h"
#include "openflow.h"
#include "wrapper.h"
#include "checks.h"
#include "ofdp_error.h"
#include "port_manager.h"
#include "switch_port.h"
#include "controller_manager.h"
#include "table_manager.h"
#include "action-tlv.h"
#include "oxm.h"
#include "stats-helper.h"
#include "mocks.h"


#define SELECT_TIMEOUT_USEC 100000 
#define MAX_SEND_QUEUE      512
#define MAX_RECV_QUEUE      512
#define PORT_NO             2
#define MAX_LEN             1024
#define TABLE_ID            1
#define GROUP_ID            2222
#define QUEUE_ID            1111
#define VLAN_ETHERTYPE      0x8888
#define MPLS_ETHERTYPE      0x7777
#define PBB_ETHERTYPE       0x6666
#define WEIGHT              11
#define WATCH_PORT          PORT_NO
#define WATCH_GROUP         22
#define MPLS_TTL            32
#define NW_TTL              16
#define MAX_ENTRIES         256
#define TABLE_NAME          "test_table"
#define NEXT_TABLE_ID       1
#define NEXT_TABLE_ID_MISS  2
#define COOKIE              0x31b33850c19f50e


extern uint16_t action_list_length( action_list ** );
extern uint16_t bucket_list_length( bucket_list ** );
extern void pack_bucket( struct ofp_bucket *ofp_bucket, bucket_list **list );
extern uint16_t count_features( void *feature, size_t feature_size );
extern uint16_t assign_instruction_ids( struct ofp_instruction *ins, instructions_capabilities *instructions_cap );
extern uint16_t assign_action_ids( struct ofp_action_header *ac_hdr, actions_capabilities *action_cap );
extern struct ofp_table_features * assign_table_features( table_features *table_feature );
extern flow_stats *retrieve_flow_stats( uint32_t *nr_stats, uint8_t table_id, uint32_t out_port, uint32_t out_group, uint64_t cookie, uint64_t cookie_mask, struct ofp_match *match );

static const uint8_t HW_ADDR[ OFP_ETH_ALEN ] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
static const char *DEV_NAME = "test_veth";


#undef get_ofp_port_structure
#define get_ofp_port_structure mock_get_ofp_port_structure
OFDPE get_ofp_port_structure( uint32_t port_no, ofp_port *out_port );



static uint16_t
all_actions_len( void ) {

  uint16_t len = 0;

  len = ( uint16_t ) ( sizeof( struct ofp_action_output ) ); 
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_group ) ); 
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_set_queue ) ); 
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_mpls_ttl ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_header ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_nw_ttl ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_header ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_header ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_header ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_push ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_push ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_push ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_header ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_pop_mpls ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_header ) );
  len = ( uint16_t ) ( len + sizeof( struct ofp_action_set_field ) );

  return len;
}


static void
create_port_desc( void **state ) {
  UNUSED( state );

  int ret = init_port_manager( SELECT_TIMEOUT_USEC, MAX_SEND_QUEUE, MAX_RECV_QUEUE );
  if ( ret != OFDPE_SUCCESS ) {
   return;
  }

  expect_string( mock_create_ether_device, name, DEV_NAME );
  expect_value( mock_create_ether_device, max_send_queue, MAX_SEND_QUEUE );
  expect_value( mock_create_ether_device, max_recv_queue, MAX_RECV_QUEUE );
  switch_port *port = ( switch_port * ) xmalloc( sizeof( switch_port ) );
  port->device = ( ether_device * ) xmalloc( sizeof( ether_device ) );
  memcpy( port->device->name, DEV_NAME, sizeof( port->device->name ) );
  memcpy( port->device->hw_addr, HW_ADDR, sizeof( port->device->hw_addr ) );
  will_return( mock_create_ether_device, port->device );

  expect_value( mock_send_for_notify_port_config, port_no, PORT_NO );
  expect_value( mock_send_for_notify_port_config, reason, OFPPR_ADD );

  char *device_name = xstrdup( DEV_NAME );
  ret = add_port( PORT_NO, device_name );
  xfree( device_name );
}


static void
create_group_features( void **state ) {
  init_group_table();
  struct ofp_group_features *features = ( struct ofp_group_features * ) xmalloc( sizeof( struct ofp_group_features ) );
  features->types = OFPGT_ALL;
  features->capabilities = OFPGFC_SELECT_WEIGHT | OFPGFC_SELECT_LIVENESS;
  features->max_groups[ OFPGT_ALL ] = 128;
  features->max_groups[ OFPGT_SELECT ] = 256;
  features->max_groups[ OFPGT_INDIRECT ] = 512;
  features->max_groups[ OFPGT_FF ] = 640;
  features->actions[ OFPGT_ALL ] = OFPAT_OUTPUT;
  features->actions[ OFPGT_SELECT ] = OFPAT_COPY_TTL_OUT;
  features->actions[ OFPGT_INDIRECT ] = OFPAT_PUSH_VLAN;
  features->actions[ OFPGT_FF ] = OFPAT_GROUP;
  set_group_features( features );
  *state = ( void * ) features;
}


static action_list *
complete_action_list( void ) {
  action_list *ac_list = init_action_list();

//  expect_value( mock_is_valid_port_no, port_no, PORT_NO );
  action *ac_output = create_action_output( PORT_NO, MAX_LEN );
  append_action( ac_list, ac_output );

  const uint32_t group_id = GROUP_ID;
  action *ac_group = create_action_group( group_id );
  append_action( ac_list, ac_group );
  
  const uint32_t queue_id = QUEUE_ID;
  action *ac_set_queue = create_action_set_queue( queue_id );
  append_action( ac_list, ac_set_queue );
  
  const uint8_t mpls_ttl = MPLS_TTL;
  action *ac_set_mpls_ttl = create_action_set_mpls_ttl( mpls_ttl );
  append_action( ac_list, ac_set_mpls_ttl );
  
  action *ac_dec_mpls_ttl = create_action_dec_mpls_ttl();
  append_action( ac_list, ac_dec_mpls_ttl );
  
  const uint8_t nw_ttl = NW_TTL;
  action *ac_set_ipv4_ttl = create_action_set_ipv4_ttl( nw_ttl );
  append_action( ac_list, ac_set_ipv4_ttl );
  

  action *ac_dec_ipv4_ttl = create_action_dec_ipv4_ttl();
  append_action( ac_list, ac_dec_ipv4_ttl );
  
  action *ac_copy_ttl_out = create_action_copy_ttl_out();
  append_action( ac_list, ac_copy_ttl_out );
  
  action *ac_copy_ttl_in = create_action_copy_ttl_in();
  append_action( ac_list, ac_copy_ttl_in );
  
  const uint16_t ether_type = VLAN_ETHERTYPE;
  action *ac_action_push_vlan = create_action_push_vlan( ether_type );
  append_action( ac_list, ac_action_push_vlan );
  

  const uint16_t mpls_type = MPLS_ETHERTYPE;
  action *ac_action_push_mpls = create_action_push_mpls( mpls_type );
  append_action( ac_list, ac_action_push_mpls );
  

  const uint16_t pbb_type = PBB_ETHERTYPE;
  action *ac_action_push_pbb = create_action_push_pbb( pbb_type );
  append_action( ac_list, ac_action_push_pbb );


  action *ac_action_pop_vlan = create_action_pop_vlan();
  append_action( ac_list, ac_action_pop_vlan );
  
  action *ac_action_pop_mpls = create_action_pop_mpls( mpls_type );
  append_action( ac_list, ac_action_pop_mpls );

  action *ac_action_pop_pbb = create_action_pop_pbb();
  append_action( ac_list, ac_action_pop_pbb );
  
  match *match = init_match();
  action *ac_action_set_field = create_action_set_field( match );
  append_action( ac_list, ac_action_set_field );
  return ac_list;
}


static void
create_action_list( void **state ) {
  action_list *ac_list = complete_action_list();

  init_actions();
  *state = ( void * ) ac_list;
}


static void
create_bucket_list( void **state ) {
  bucket_list *bkt_list = create_action_bucket_list();

  action_list *ac_list = complete_action_list();
  const uint16_t weight = WEIGHT;
  const uint32_t watch_port = WATCH_PORT;
  const uint32_t watch_group = WATCH_GROUP;

//  expect_value( mock_is_valid_port_no, port_no, watch_port );
  bucket *bkt = create_action_bucket( weight, watch_port, watch_group, ac_list );
  if ( bkt != NULL ) {
    append_action_bucket( bkt_list, bkt );
  }
  init_actions();
  *state = ( void * ) bkt_list;
}


static void
destroy_port_desc( void **state ) {
  UNUSED( state );
  finalize_port_manager();
}


static void
destroy_group_features( void **state ) {
  UNUSED( state );
  finalize_group_table();
}


static void
destroy_action_list( void **state ) {
  action_list *ac_list = *state;

  finalize_action_list( &ac_list );
  finalize_actions();
}


static void
destroy_bucket_list( void **state ) {
  bucket_list *bkt_list = *state;

  delete_action_bucket_list( &bkt_list );
  finalize_actions();
}


static void
test_request_port_desc( void **state ) {
  UNUSED( state );

  list_element *list = request_port_desc();
  assert_true( list );
  struct ofp_port *ofp_port = list->data;
  assert_int_equal( ofp_port->port_no, PORT_NO );
  assert_string_equal( ofp_port->name, DEV_NAME );
  assert_memory_equal( ofp_port->hw_addr, HW_ADDR, sizeof( ofp_port->hw_addr ) );
}


static void
test_request_group_features( void **state ) {
  struct ofp_group_features *set_features = *state;
  struct ofp_group_features *features;
  
  features = request_group_features();
  assert_true( features );
  assert_memory_equal( features, set_features, sizeof( *features ) );
}


static void
test_action_list_length( void **state ) {
  action_list *ac_list = *state;

  uint16_t expected_len = all_actions_len();;
  uint16_t len = action_list_length( &ac_list );
  assert_int_equal( len, expected_len );
}


static void
test_bucket_list_length( void **state ) {
  bucket_list *bkt_list = *state;

  uint16_t expected_len = all_actions_len();

  expected_len = ( uint16_t ) ( expected_len + sizeof( struct ofp_bucket ) );

  uint16_t len = bucket_list_length( &bkt_list );
  assert_int_equal( len, expected_len );
}


static void
test_pack_bucket( void **state ) {
  bucket_list *bkt_list = *state;
  struct ofp_bucket *bucket;

  uint16_t bucket_len = ( uint16_t ) ( sizeof( *bucket ) + all_actions_len() );

  bucket = ( struct ofp_bucket * ) xmalloc( bucket_len );
  pack_bucket( bucket, &bkt_list );
  assert_int_equal( bucket->weight, WEIGHT );
  assert_int_equal( bucket->watch_port, WATCH_PORT );
  assert_int_equal( bucket->watch_group, WATCH_GROUP );

  const struct ofp_action_output const *ac_output = ( const struct ofp_action_output const * ) &bucket->actions[ 0 ];
  assert_int_equal( ac_output->type, OFPAT_OUTPUT );
  assert_int_equal( ac_output->len, sizeof( *ac_output ) );
  assert_int_equal( ac_output->port, PORT_NO );
  assert_int_equal( ac_output->max_len, MAX_LEN );

  const struct ofp_action_group const *ac_group = ( const struct ofp_action_group const * )( ( const char const * ) ac_output + ac_output->len );
  assert_int_equal( ac_group->type, OFPAT_GROUP );
  assert_int_equal( ac_group->len, sizeof ( *ac_group ) );
  assert_int_equal( ac_group->group_id, GROUP_ID );

  const struct ofp_action_set_queue const *ac_set_queue = ( const struct ofp_action_set_queue const * )( ( const char const * ) ac_group + ac_group->len );
  assert_int_equal( ac_set_queue->type, OFPAT_SET_QUEUE );
  assert_int_equal( ac_set_queue->len, sizeof( *ac_set_queue ) );
  assert_int_equal( ac_set_queue->queue_id, QUEUE_ID );

  const struct ofp_action_mpls_ttl *ac_set_mpls_ttl = ( const struct ofp_action_mpls_ttl const * )( ( const char const * ) ac_set_queue + ac_set_queue->len );
  assert_int_equal( ac_set_mpls_ttl->type, OFPAT_SET_MPLS_TTL );
  assert_int_equal( ac_set_mpls_ttl->len, sizeof( *ac_set_mpls_ttl ) );
  assert_int_equal( ac_set_mpls_ttl->mpls_ttl, MPLS_TTL );
  
  const struct ofp_action_header const *ac_dec_mpls_ttl = ( const struct ofp_action_header const * )( ( const char const * ) ac_set_mpls_ttl + ac_set_mpls_ttl->len );
  assert_int_equal( ac_dec_mpls_ttl->type, OFPAT_DEC_MPLS_TTL );
  assert_int_equal( ac_dec_mpls_ttl->len, sizeof( *ac_dec_mpls_ttl ) );

  const struct ofp_action_nw_ttl const *ac_set_nw_ttl = ( const struct ofp_action_nw_ttl const * )( ( const char const * ) ac_dec_mpls_ttl + ac_dec_mpls_ttl->len );
  assert_int_equal( ac_set_nw_ttl->type, OFPAT_SET_NW_TTL );
  assert_int_equal( ac_set_nw_ttl->len, sizeof( *ac_set_nw_ttl ) );
  assert_int_equal( ac_set_nw_ttl->nw_ttl, NW_TTL );
  
  const struct ofp_action_header const *ac_dec_nw_ttl = ( const struct ofp_action_header const * )( ( const char const * ) ac_set_nw_ttl + ac_set_nw_ttl->len );
  assert_int_equal( ac_dec_nw_ttl->type, OFPAT_DEC_NW_TTL );
  assert_int_equal( ac_dec_nw_ttl->len, sizeof( *ac_dec_nw_ttl ) );
  
  const struct ofp_action_header const *ac_copy_ttl_out = ( const struct ofp_action_header const * )( ( const char const * ) ac_dec_nw_ttl + ac_dec_nw_ttl->len );
  assert_int_equal( ac_copy_ttl_out->type, OFPAT_COPY_TTL_OUT );
  assert_int_equal( ac_copy_ttl_out->len, sizeof( *ac_copy_ttl_out ) );
  
  const struct ofp_action_header const *ac_copy_ttl_in = ( const struct ofp_action_header const * )( ( const char const * ) ac_copy_ttl_out + ac_copy_ttl_out->len );
  assert_int_equal( ac_copy_ttl_in->type, OFPAT_COPY_TTL_IN );
  assert_int_equal( ac_copy_ttl_in->len, sizeof( *ac_copy_ttl_in ) );
  
  const struct ofp_action_push const *ac_action_push_vlan = ( const struct ofp_action_push const * )( ( const char const * ) ac_copy_ttl_in + ac_copy_ttl_in->len );
  assert_int_equal( ac_action_push_vlan->type, OFPAT_PUSH_VLAN );
  assert_int_equal( ac_action_push_vlan->len, sizeof( *ac_action_push_vlan ) );
  assert_int_equal( ac_action_push_vlan->ethertype, VLAN_ETHERTYPE );

  const struct ofp_action_push const *ac_action_push_mpls = ( const struct ofp_action_push const * )( ( const char const * ) ac_action_push_vlan + ac_action_push_vlan->len );
  assert_int_equal( ac_action_push_mpls->type, OFPAT_PUSH_MPLS );
  assert_int_equal( ac_action_push_mpls->len, sizeof( *ac_action_push_mpls ) );
  assert_int_equal( ac_action_push_mpls->ethertype, MPLS_ETHERTYPE );

  const struct ofp_action_push const *ac_action_push_pbb = ( const struct ofp_action_push const * )( ( const char const * ) ac_action_push_mpls + ac_action_push_mpls->len );
  assert_int_equal( ac_action_push_pbb->type, OFPAT_PUSH_PBB );
  assert_int_equal( ac_action_push_pbb->len, sizeof ( *ac_action_push_pbb ) );
  assert_int_equal( ac_action_push_pbb->ethertype, PBB_ETHERTYPE );
  
  const struct ofp_action_header const *ac_pop_vlan = ( const struct ofp_action_header const * )( ( const char const * ) ac_action_push_pbb + ac_action_push_pbb->len );
  assert_int_equal( ac_pop_vlan->type, OFPAT_POP_VLAN );
  assert_int_equal( ac_pop_vlan->len, sizeof( *ac_pop_vlan ) );
  
  const struct ofp_action_pop_mpls const *ac_pop_mpls = ( const struct ofp_action_pop_mpls const * )( ( const char const * ) ac_pop_vlan + ac_pop_vlan->len );
  assert_int_equal( ac_pop_mpls->type, OFPAT_POP_MPLS );
  assert_int_equal( ac_pop_mpls->len, sizeof( *ac_pop_mpls ) );
  assert_int_equal( ac_pop_mpls->ethertype, MPLS_ETHERTYPE );

  const struct ofp_action_header const *ac_pop_pbb = ( const struct ofp_action_header const * )( ( const char const * ) ac_pop_mpls + ac_pop_mpls->len );
  assert_int_equal( ac_pop_pbb->type, OFPAT_POP_PBB );
  assert_int_equal( ac_pop_pbb->len, sizeof( *ac_pop_pbb ) );

  const struct ofp_action_set_field const *ac_set_field = ( const struct ofp_action_set_field const * )( ( const char const * ) ac_pop_pbb + ac_pop_pbb->len );
  assert_int_equal( ac_set_field->type, OFPAT_SET_FIELD );
  assert_int_equal( ac_set_field->len, sizeof( *ac_set_field ) );
}


static void
test_count_features( void **state ) {
  UNUSED( state );
  
  instructions_capabilities *ins_cap = ( instructions_capabilities * ) xcalloc( 1, sizeof( *ins_cap ) );
  uint16_t feature_len;
  
  feature_len = count_features( ( void * ) ins_cap, sizeof( *ins_cap ) );
  assert_int_equal( feature_len, 0 );
  
  // test setting all the attributes to true
  memset( ins_cap, 1, sizeof( *ins_cap ) );
  feature_len = count_features( ( void * ) ins_cap, sizeof( *ins_cap ) );
  assert_int_equal( feature_len, 6 );
  
  // test setting the first and last attribute
  memset( ins_cap, 0, sizeof( *ins_cap ) );
  ins_cap->meter = true;
  ins_cap->goto_table = true;
  feature_len = count_features( ( void * ) ins_cap, sizeof( *ins_cap ) );
  assert_int_equal( feature_len, 2 );
  
  // test some attributes found around the middle of the structure.
  memset( ins_cap, 0, sizeof( *ins_cap ) );
  ins_cap->clear_actions = true;
  ins_cap->write_actions = true;
  ins_cap->write_metadata = true;
  feature_len = count_features( ( void * ) ins_cap, sizeof( *ins_cap ) );
  assert_int_equal( feature_len, 3 );
  xfree( ins_cap );
  
}


static void
assert_instruction( const struct ofp_instruction *instruction, const instructions_capabilities *ins_cap ) {
  assert_int_equal( instruction->len, sizeof( struct ofp_instruction ) );
  if ( instruction->type == OFPIT_METER  ) {
    assert_int_equal( ins_cap->meter, true );
  }
  else if ( instruction->type == OFPIT_APPLY_ACTIONS ) {
    assert_int_equal( ins_cap->apply_actions, true );
  }
  else if ( instruction->type ==  OFPIT_CLEAR_ACTIONS ) {
    assert_int_equal( ins_cap->clear_actions, true );
  }
  else if ( instruction->type == OFPIT_WRITE_ACTIONS ) {
    assert_int_equal( ins_cap->write_actions, true );
  }
  else if ( instruction->type == OFPIT_WRITE_METADATA ) {
    assert_int_equal( ins_cap->write_metadata, true );
  }
  else if ( instruction->type == OFPIT_GOTO_TABLE ) {
    assert_int_equal( ins_cap->goto_table, true );
  }
}


static void
test_assign_instruction_ids( void **state ) {
  UNUSED( state );
  
  instructions_capabilities *ins_cap = ( instructions_capabilities * ) xmalloc( sizeof( *ins_cap ) );
  uint16_t feature_len;
  
  // test setting all the instructions
  memset( ins_cap, 1, sizeof( *ins_cap ) );
  
  feature_len = count_features( ( void * ) ins_cap, sizeof( *ins_cap ) );
  // allocate space for all ofp_instruction
  struct ofp_instruction *instructions = ( struct ofp_instruction * ) xmalloc( feature_len * sizeof( *instructions ) );
  uint16_t total_len = assign_instruction_ids( instructions, ins_cap );
  for ( uint16_t i = 0; i < feature_len; i++) {
    assert_instruction( &instructions[ i ], ins_cap );
  }
  assert_int_equal( total_len, feature_len * sizeof( struct ofp_instruction ) );
  xfree( instructions );
  xfree( ins_cap );
}


static void
assert_action_ids( const struct ofp_action_header *ac_hdr, const actions_capabilities *ac_cap ) {
  assert_int_equal( ac_hdr->len, sizeof( struct ofp_action_header ) );
  if ( ac_hdr->type == OFPAT_OUTPUT ) {
    assert_int_equal( ac_cap->output, true );
  }
  else if ( ac_hdr->type == OFPAT_SET_QUEUE ) {
    assert_int_equal( ac_cap->set_queue, true );
  }
  else if ( ac_hdr->type == OFPAT_GROUP ) {
    assert_int_equal( ac_cap->group, true );
  }
  else if ( ac_hdr->type == OFPAT_PUSH_VLAN ) {
    assert_int_equal( ac_cap->push_vlan, true );
  }
  else if ( ac_hdr->type == OFPAT_POP_VLAN ) {
    assert_int_equal( ac_cap->pop_vlan, true );
  }
  else if ( ac_hdr->type == OFPAT_PUSH_MPLS ) {
    assert_int_equal( ac_cap->push_mpls, true );
  }
  else if ( ac_hdr->type == OFPAT_POP_MPLS ) {
    assert_int_equal( ac_cap->pop_mpls, true );
  }
  else if ( ac_hdr->type == OFPAT_PUSH_PBB ) {
    assert_int_equal( ac_cap->push_pbb, true );
  }
  else if ( ac_hdr->type == OFPAT_POP_PBB ) {
    assert_int_equal( ac_cap->pop_pbb, true );
  }
}


static void
test_assign_action_ids( void **state ) {
  UNUSED( state );

  actions_capabilities *ac_cap = ( actions_capabilities * ) xmalloc( sizeof( *ac_cap ) );
  uint16_t feature_len;

  memset( ac_cap, 1, sizeof( *ac_cap ) );
  ac_cap->drop = false;
  feature_len = count_features( ( void * ) ac_cap, sizeof( *ac_cap ) );
  struct ofp_action_header *ac_hdr = ( struct ofp_action_header * ) xmalloc( feature_len * sizeof( *ac_hdr ) );
  uint16_t total_len = assign_action_ids( ac_hdr, ac_cap );
  for ( uint16_t i = 0; i < feature_len; i++ ) {
    assert_action_ids( &ac_hdr[ i ], ac_cap );
  }
  assert_int_equal( total_len, feature_len * sizeof( struct ofp_action_header ) );
  xfree( ac_hdr );
  xfree( ac_cap );
}


static void
assert_table_feature_prop_actions( const struct ofp_table_feature_prop_actions const *tfpa, uint16_t type ) {
  uint16_t expected_len = ( uint16_t ) sizeof( *tfpa );

  assert_int_equal( tfpa->type, type );
  const struct ofp_action_header const *ac_id = tfpa->action_ids;
  assert_int_equal( ac_id->type, OFPAT_OUTPUT );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 1 ];
  assert_int_equal( ac_id->type, OFPAT_SET_QUEUE );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 2 ];
  assert_int_equal( ac_id->type, OFPAT_GROUP );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 3 ];
  assert_int_equal( ac_id->type, OFPAT_PUSH_VLAN );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 4 ];
  assert_int_equal( ac_id->type, OFPAT_POP_VLAN );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 5 ];
  assert_int_equal( ac_id->type, OFPAT_PUSH_MPLS );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );
  
  ac_id = &tfpa->action_ids[ 6 ]; 
  assert_int_equal( ac_id->type, OFPAT_POP_MPLS );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 7 ];
  assert_int_equal( ac_id->type, OFPAT_PUSH_PBB );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );

  ac_id = &tfpa->action_ids[ 8 ];
  assert_int_equal( ac_id->type, OFPAT_POP_PBB );
  assert_int_equal( ac_id->len, sizeof( *ac_id ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *ac_id ) );


  expected_len = ( uint16_t ) ( expected_len + PADLEN_TO_64( expected_len ) );
  assert_int_equal( tfpa->length, expected_len );
}


static void
assert_table_feature_prop_instructions( const struct ofp_table_feature_prop_instructions *tfpi, uint16_t type ) {
  uint16_t expected_len = ( uint16_t ) sizeof( *tfpi );

  assert_int_equal( tfpi->type, type );
  const struct ofp_instruction const *instruction = &tfpi->instruction_ids[ 0 ];
  assert_int_equal( instruction->type, OFPIT_METER );
  assert_int_equal( instruction->len, sizeof( *instruction ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *instruction ) );

  instruction = &tfpi->instruction_ids[ 1 ];
  assert_int_equal( instruction->type, OFPIT_APPLY_ACTIONS );
  assert_int_equal( instruction->len, sizeof( *instruction ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *instruction ) );

  instruction = &tfpi->instruction_ids[ 2 ];
  assert_int_equal( instruction->type, OFPIT_CLEAR_ACTIONS );
  assert_int_equal( instruction->len, sizeof( *instruction ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *instruction ) );

  instruction = &tfpi->instruction_ids[ 3 ];
  assert_int_equal( instruction->type, OFPIT_WRITE_ACTIONS );
  assert_int_equal( instruction->len, sizeof( *instruction ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *instruction ) );

  instruction = &tfpi->instruction_ids[ 4 ];
  assert_int_equal( instruction->type, OFPIT_WRITE_METADATA );
  assert_int_equal( instruction->len, sizeof( *instruction ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *instruction ) );

  instruction = &tfpi->instruction_ids[ 5 ];
  assert_int_equal( instruction->type, OFPIT_GOTO_TABLE );
  assert_int_equal( instruction->len, sizeof( *instruction ) );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *instruction ) );


  expected_len = ( uint16_t ) ( expected_len + PADLEN_TO_64( expected_len ) );
  assert_int_equal( tfpi->length, expected_len );
}


static void
assert_table_feature_prop_oxm( const struct ofp_table_feature_prop_oxm const *tfpo, uint16_t type ) {
  uint16_t expected_len = ( uint16_t ) sizeof( *tfpo );

  assert_int_equal( tfpo->type, type );
  const uint32_t const *oxm_id = ( const uint32_t const * ) &tfpo->oxm_ids[ 0 ];
  assert_int_equal( *oxm_id, OXM_OF_IN_PORT );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IN_PHY_PORT );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_METADATA );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ETH_DST );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ETH_SRC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ETH_TYPE );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_VLAN_VID );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_VLAN_PCP );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IP_DSCP );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IP_ECN );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IP_PROTO );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV4_SRC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV4_DST );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_TCP_SRC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_TCP_DST );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_UDP_SRC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_UDP_DST );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_SCTP_SRC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_SCTP_DST );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ICMPV4_TYPE );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ICMPV4_CODE );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ARP_OP );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ARP_SPA );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ARP_TPA );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ARP_SHA );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ARP_THA );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_SRC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_DST );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_FLABEL );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ICMPV6_TYPE );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_ICMPV6_CODE );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_ND_TARGET );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_ND_SLL );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_ND_TLL );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_MPLS_LABEL );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_MPLS_TC );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_MPLS_BOS );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );
  // comment out until datapath's match field is created
  // oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  // assert_int_equal( *oxm_id, OXM_OF_PBB_ISID );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_TUNNEL_ID );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  oxm_id = ( const uint32_t const * ) ( ( const char const * ) oxm_id + sizeof( uint32_t ) ); 
  assert_int_equal( *oxm_id, OXM_OF_IPV6_EXTHDR );
  expected_len = ( uint16_t ) ( expected_len + sizeof( *oxm_id ) );

  expected_len = ( uint16_t ) ( expected_len + PADLEN_TO_64( expected_len ) );
  assert_int_equal( tfpo->length, expected_len );
}


static void
assert_table_feature_prop_next_tables( const struct ofp_table_feature_prop_next_tables const *tfpnt, uint16_t type ) {
  uint16_t expected_len = ( uint16_t ) sizeof( *tfpnt );

  assert_int_equal( tfpnt->type, type );

  expected_len = ( uint16_t ) ( expected_len + PADLEN_TO_64( expected_len ) );
  assert_int_equal( tfpnt->length, expected_len );
}


static void
test_assign_table_features( void **state ) {
  UNUSED( state );

  table_features *features = ( table_features * ) xmalloc( sizeof( *features ) );
  features->table_id = 0;
  strncpy( features->name, TABLE_NAME, OFP_MAX_TABLE_NAME_LEN );
  features->name[ OFP_MAX_TABLE_NAME_LEN - 1 ] = '\0';
  features->metadata_match = UINT64_MAX; 
  features->metadata_write = UINT64_MAX;
  features->config = OFPTC_DEPRECATED_MASK;
  features->max_entries = MAX_ENTRIES;
  memset( &features->instructions, 1, sizeof( features->instructions ) );
  memset( &features->instructions_miss, 1, sizeof( features->instructions_miss ) );
  features->min_next_table_ids = NEXT_TABLE_ID;
  features->min_next_table_ids_miss = NEXT_TABLE_ID_MISS;
  memset( &features->write_actions, 1, sizeof( features->write_actions ) );
  memset( &features->write_actions_miss, 1, sizeof( features->write_actions_miss ) );
  memset( &features->apply_actions, 1, sizeof( features->apply_actions ) );
  memset( &features->apply_actions_miss, 1, sizeof( features->apply_actions_miss ) );
  memset( &features->matches, 1, sizeof( features->matches ) );
  memset( &features->wildcards, 1, sizeof( features->wildcards ) );
  memset( &features->write_setfield, 1, sizeof( features->write_setfield ) );
  memset( &features->write_setfield_miss, 1, sizeof( features->write_setfield_miss ) );
  memset( &features->apply_setfield, 1, sizeof( features->apply_setfield ) );
  memset( &features->apply_setfield_miss, 1, sizeof( features->apply_setfield_miss ) );

  init_oxm();
  struct ofp_table_features *ofp_table_features  = assign_table_features( features );
  assert_int_equal( ofp_table_features->table_id, 0 );
  assert_string_equal( ofp_table_features->name, TABLE_NAME );
  assert_int_equal( ofp_table_features->metadata_match, UINT64_MAX );
  assert_int_equal( ofp_table_features->metadata_write, UINT64_MAX );
  assert_int_equal( ofp_table_features->config, OFPTC_DEPRECATED_MASK );
  assert_int_equal( ofp_table_features->max_entries, MAX_ENTRIES );

  const struct ofp_table_feature_prop_instructions const *tfpi = ( const struct ofp_table_feature_prop_instructions const * ) &ofp_table_features->properties[ 0 ];
  assert_table_feature_prop_instructions( tfpi, OFPTFPT_INSTRUCTIONS ); 

  tfpi = ( const struct ofp_table_feature_prop_instructions const * )( ( const char const * ) tfpi + tfpi->length );
  assert_table_feature_prop_instructions( tfpi, OFPTFPT_INSTRUCTIONS_MISS );

  const struct ofp_table_feature_prop_actions *tfpa = ( const struct ofp_table_feature_prop_actions const * ) ( ( const char const * ) tfpi + tfpi->length );
  assert_table_feature_prop_actions( tfpa, OFPTFPT_WRITE_ACTIONS );

  tfpa = ( const struct ofp_table_feature_prop_actions  const * ) ( ( const char const * ) tfpa + tfpa->length );
  assert_table_feature_prop_actions( tfpa, OFPTFPT_WRITE_ACTIONS_MISS );

  tfpa = ( const struct ofp_table_feature_prop_actions const * ) ( ( const char const * ) tfpa + tfpa->length );
  assert_table_feature_prop_actions( tfpa, OFPTFPT_APPLY_ACTIONS );

  tfpa = ( const struct ofp_table_feature_prop_actions const * ) ( ( const char const * ) tfpa + tfpa->length );
  assert_table_feature_prop_actions( tfpa, OFPTFPT_APPLY_ACTIONS_MISS );

  const struct ofp_table_feature_prop_oxm const *tfpo = ( const struct ofp_table_feature_prop_oxm const * ) ( ( const char const * ) tfpa + tfpa->length );
  assert_table_feature_prop_oxm( tfpo, OFPTFPT_MATCH );

  tfpo = ( const struct ofp_table_feature_prop_oxm const * ) ( ( const char const * ) tfpo + tfpo->length );
  assert_table_feature_prop_oxm( tfpo, OFPTFPT_WILDCARDS );

  tfpo = ( const struct ofp_table_feature_prop_oxm const * ) ( ( const char const * ) tfpo + tfpo->length );
  assert_table_feature_prop_oxm( tfpo, OFPTFPT_WRITE_SETFIELD );

  tfpo = ( const struct ofp_table_feature_prop_oxm const * ) ( ( const char const * ) tfpo + tfpo->length );
  assert_table_feature_prop_oxm( tfpo, OFPTFPT_WRITE_SETFIELD_MISS );

  tfpo = ( const struct ofp_table_feature_prop_oxm const * ) ( ( const char const * ) tfpo + tfpo->length );
  assert_table_feature_prop_oxm( tfpo, OFPTFPT_APPLY_SETFIELD );

  tfpo = ( const struct ofp_table_feature_prop_oxm const * ) ( ( const char const * ) tfpo + tfpo->length ); 
  assert_table_feature_prop_oxm( tfpo, OFPTFPT_APPLY_SETFIELD_MISS );
  
  const struct ofp_table_feature_prop_next_tables *tfpnt = ( const struct ofp_table_feature_prop_next_tables const * ) ( ( const char const * ) tfpo + tfpo->length ); 
  assert_table_feature_prop_next_tables( tfpnt, OFPTFPT_NEXT_TABLES );
  const uint8_t const *table_id = ( const uint8_t const * ) ( &tfpnt->next_table_ids );
  assert_int_equal( *table_id, NEXT_TABLE_ID );

  tfpnt = ( const struct ofp_table_feature_prop_next_tables const * ) ( ( const char const * ) tfpnt + tfpnt->length );
  assert_table_feature_prop_next_tables( tfpnt, OFPTFPT_NEXT_TABLES_MISS );
  table_id = ( const uint8_t const * ) ( &tfpnt->next_table_ids );
  assert_int_equal( *table_id, NEXT_TABLE_ID_MISS );
}


static void
test_retrieve_flow_stats( void **state ) {
  UNUSED( state );

  uint16_t total_len = ( uint16_t ) ( sizeof( struct ofp_match ) +
    OXM_LENGTH( OXM_OF_IN_PORT ) +
    sizeof( uint32_t ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) + 
    sizeof( uint32_t ) + OXM_LENGTH ( OXM_OF_METADATA )
  );
  total_len = ( uint16_t ) ( total_len + PADLEN_TO_64( total_len ) );
  struct ofp_match *ofp_match =  ( struct ofp_match * ) ( xmalloc( total_len ) );
  ofp_match->type = OFPMT_OXM;
  ofp_match->length = total_len;

  uint32_t *oxm_id = ( uint32_t * ) ( ( char * ) ofp_match->oxm_fields );
  *oxm_id = OXM_OF_IN_PORT;

  uint32_t *in_port = ( uint32_t * ) ( ( char * ) oxm_id + sizeof( *oxm_id ) );
  *in_port = PORT_NO;

  oxm_id = ( uint32_t * ) ( ( char * ) in_port + OXM_LENGTH( OXM_OF_IN_PORT ) );
  *oxm_id = OXM_OF_IN_PHY_PORT;

  uint32_t *in_phy_port = ( uint32_t * ) ( ( char * ) oxm_id + sizeof( *oxm_id ) );
  *in_phy_port = PORT_NO;

  oxm_id = ( uint32_t * ) ( ( char * ) in_phy_port + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  *oxm_id = OXM_OF_METADATA;

  uint64_t *metadata = ( uint64_t * ) ( ( char * ) oxm_id + sizeof( *oxm_id ) );
  uint64_t dummy_metadata = 0x1122334455667788;
  memcpy( metadata, &dummy_metadata, sizeof( uint64_t ) );
  
  uint32_t nr_stats = 0;
  uint8_t table_id = TABLE_ID;
  uint32_t out_port = PORT_NO;
  uint32_t out_group = GROUP_ID;
  uint64_t cookie = COOKIE;
  uint64_t cookie_mask = 0xffffffffffffffff;
  init_table_manager();
  retrieve_flow_stats( &nr_stats, table_id, out_port, out_group, cookie, cookie_mask, ofp_match );
  assert_int_equal( nr_stats, 0 );
}


static void
test_desc_stats( void **state ) {
  UNUSED( state );

  assert_string_equal( dp_desc(), "Trema-based OpenFlow switch" );
  assert_string_equal( mfr_desc(), "Trema project" );
  assert_string_equal( serial_num(), "0" );
  const char *desc = hw_desc();
  assert_true( strlen( desc ) > 0 );
}


static void
test_instructions( void **state ) {
  UNUSED( state );
  uint64_t metadata = 0x5dd2ca2bcd04d53e;
  uint64_t metadata_mask = 0x3012174b861ea4fd;
  instruction *metadata_ins = create_instruction_write_metadata( metadata, metadata_mask );
  instruction_list *ins_list = init_instruction_list();
  append_instruction( ins_list, metadata_ins );

  instruction *meter = create_instruction_meter( 0xc7231908 );
  append_instruction( ins_list, meter );
  
  instruction *apply_actions = create_instruction_apply_actions( complete_action_list() );
  append_instruction( ins_list, apply_actions );
  
  instruction *clear_actions = create_instruction_clear_actions();
  append_instruction( ins_list, clear_actions );

  dlist_element *e = get_first_element( ins_list );
  if ( e->data == NULL ) {
    e = ins_list->next;
  }
  for (; e; e = e->next ) {
    if ( e->data != NULL ) {
      instruction *ins = e->data;
      printf( "ins type( %u )\n", ins->type );
    }
  }
  instruction_list *new_ins_list;
  new_ins_list = copy_instruction_list( ins_list );
  
  remove_instruction( ins_list, meter );
  e = get_first_element( ins_list );
  if ( e->data == NULL ) {
    e = ins_list->next;
  }
  for (; e; e = e->next ) {
    if ( e->data != NULL ) {
      instruction *ins = e->data;
      printf( "ad ins type( %u )\n", ins->type );
    }
  }

  
  e = get_first_element( new_ins_list );
  if ( e->data == NULL ) {
    e = new_ins_list->next;
  }
  for (; e; e = e->next ) {
    if ( e->data != NULL ) {
      instruction *ins = e->data;
      printf( "ins type( %u )\n", ins->type );
    }
  }
  finalize_instruction_list( &new_ins_list );
  finalize_instruction_list( &ins_list );
}


static void
test_bucket_list( void **state ) {
  bucket_list *bkt_list = *state;

  action_list *ac_list = complete_action_list();
  const uint16_t weight = WEIGHT + 1;
  const uint32_t watch_port = WATCH_PORT + 1;
  const uint32_t watch_group = WATCH_GROUP + 1;

  expect_value( mock_is_valid_group_no, group_id, GROUP_ID );
  expect_value( mock_is_valid_group_no, group_id, GROUP_ID );
  bucket *bkt = create_action_bucket( weight, watch_port, watch_group, ac_list );
  if ( bkt != NULL ) {
    append_action_bucket( bkt_list, bkt );
  }

  validate_action_bucket( bkt_list );
  uint32_t bkt_cnt;
  bkt_cnt = get_bucket_count( bkt_list );
  assert_int_equal( bkt_cnt, 2 );
  remove_action_bucket( bkt_list, bkt );
  bkt_cnt = get_bucket_count( bkt_list );
  assert_int_equal( bkt_cnt, 1 );
}


int
main( void ) {
  const UnitTest tests[] = {
    unit_test( test_instructions ),
    unit_test_setup_teardown( test_bucket_list, create_bucket_list, destroy_bucket_list ),
    unit_test_setup_teardown( test_request_port_desc, create_port_desc, destroy_port_desc ),
    unit_test_setup_teardown( test_request_group_features, create_group_features, destroy_group_features ),
    unit_test_setup_teardown( test_action_list_length, create_action_list, destroy_action_list ),
    unit_test_setup_teardown( test_bucket_list_length, create_bucket_list, destroy_bucket_list ),
    unit_test_setup_teardown( test_pack_bucket, create_bucket_list, destroy_bucket_list ),
    unit_test( test_count_features ),
    unit_test( test_assign_instruction_ids ),
    unit_test( test_assign_action_ids ),
    unit_test( test_assign_table_features ),
    unit_test( test_retrieve_flow_stats ),
    unit_test( test_desc_stats ),
  };
  return run_tests( tests );
}


/*
 * Local variables:
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * End:
*/