trema/trema-edge

View on GitHub
src/lib/byteorder.c

Summary

Maintainability
Test Coverage
/*
 * Author: Yasunobu Chiba
 *
 * 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 <arpa/inet.h>
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <strings.h>
#include "byteorder.h"
#include "log.h"
#include "wrapper.h"
#include "oxm_byteorder.h"


void
ntoh_hello_elem_versionbitmap( struct ofp_hello_elem_versionbitmap *dst, const struct ofp_hello_elem_versionbitmap *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->type ) == OFPHET_VERSIONBITMAP );

  dst->type = ntohs( src->type );
  dst->length = ntohs( src->length );

  size_t n_bitmaps = ( dst->length - offsetof( struct ofp_hello_elem_versionbitmap, bitmaps ) ) / sizeof( uint32_t );

  for ( size_t i = 0; i < n_bitmaps; i++ ) {
    dst->bitmaps[ i ] = ntohl( src->bitmaps[ i ] );
  }
}


void
hton_hello_elem_versionbitmap( struct ofp_hello_elem_versionbitmap *dst, const struct ofp_hello_elem_versionbitmap *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->type == OFPHET_VERSIONBITMAP );

  size_t n_bitmaps = ( src->length - offsetof( struct ofp_hello_elem_versionbitmap, bitmaps ) ) / sizeof( uint32_t );

  dst->type = htons( src->type );
  dst->length = htons( src->length );

  for ( size_t i = 0; i < n_bitmaps; i++ ) {
    dst->bitmaps[ i ] = htonl( src->bitmaps[ i ] );
  }
}


void
ntoh_hello_elem( struct ofp_hello_elem_header *dst, const struct ofp_hello_elem_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( ntohs( src->type ) ) {
    case OFPHET_VERSIONBITMAP:
    {
      ntoh_hello_elem_versionbitmap( ( struct ofp_hello_elem_versionbitmap * ) dst,
                                     ( const struct ofp_hello_elem_versionbitmap * ) src );
    }
    break;

    default:
    {
      die( "Undefined hello element type ( type = %#x ).", ntohs( src->type ) );
    }
    break;
  }
}


void
hton_hello_elem( struct ofp_hello_elem_header *dst, const struct ofp_hello_elem_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( src->type ) {
    case OFPHET_VERSIONBITMAP:
    {
      hton_hello_elem_versionbitmap( ( struct ofp_hello_elem_versionbitmap * ) dst,
                                     ( const struct ofp_hello_elem_versionbitmap * ) src );
    }
    break;

    default:
    {
      die( "Undefined hello element type ( type = %#x ).", src->type );
    }
    break;
  }
}


void
ntoh_port( struct ofp_port *dst, const struct ofp_port *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->port_no = ntohl( src->port_no );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  memmove( dst->hw_addr, src->hw_addr, OFP_ETH_ALEN );
  memset( &dst->pad2, 0, sizeof( dst->pad2 ) );

  memmove( dst->name, src->name, OFP_MAX_PORT_NAME_LEN );

  dst->config = ntohl( src->config );
  dst->state = ntohl( src->state );

  dst->curr = ntohl( src->curr );
  dst->advertised = ntohl( src->advertised );
  dst->supported = ntohl( src->supported );
  dst->peer = ntohl( src->peer );

  dst->curr_speed = ntohl( src->curr_speed );
  dst->max_speed = ntohl( src->max_speed );
}


void
ntoh_action_output( struct ofp_action_output *dst, const struct ofp_action_output *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->port = ntohl( src->port );
  dst->max_len = ntohs( src->max_len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void ntoh_action_set_field( struct ofp_action_set_field *dst, const struct ofp_action_set_field *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->len ) != 0 );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );

  size_t field_length = dst->len - offsetof( struct ofp_action_set_field, field );
  if ( field_length > sizeof( oxm_match_header ) ) {
    const oxm_match_header *s_oxm = ( const oxm_match_header * ) src->field;
    oxm_match_header *d_oxm = ( oxm_match_header * ) dst->field;
    ntoh_oxm_match( d_oxm, s_oxm );
  }
  else {
    memset( dst->field, 0, field_length );
  }
}


void hton_action_set_field( struct ofp_action_set_field *dst, const struct ofp_action_set_field *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->len != 0 );

  dst->type = htons( src->type );
  dst->len = htons( src->len );

  size_t field_length = ntohs( dst->len ) - offsetof( struct ofp_action_set_field, field );
  if ( field_length > sizeof( oxm_match_header ) ) {
    const oxm_match_header *s_oxm = ( const oxm_match_header * ) src->field;
    oxm_match_header *d_oxm = ( oxm_match_header * ) dst->field;
    hton_oxm_match( d_oxm, s_oxm );
  }
  else {
    memset( dst->field, 0, field_length );
  }
}


void
ntoh_action_set_queue( struct ofp_action_set_queue *dst, const struct ofp_action_set_queue *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->queue_id = ntohl( src->queue_id );
}


void
ntoh_action_experimenter( struct ofp_action_experimenter_header *dst, const struct ofp_action_experimenter_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->experimenter = ntohl( src->experimenter );

  uint16_t offset = ( uint16_t ) sizeof( struct ofp_action_experimenter_header );
  if ( dst->len > offset ) {
    uint16_t data_length = ( uint16_t ) ( dst->len - offset );
    memmove( ( char * ) dst + offset, ( const char * ) src + offset, data_length );
  }
}


void
hton_action_experimenter( struct ofp_action_experimenter_header *dst, const struct ofp_action_experimenter_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = htons( src->type );
  dst->len = htons( src->len );
  dst->experimenter = htonl( src->experimenter );

  uint16_t offset = sizeof( struct ofp_action_experimenter_header );
  if ( ntohs( dst->len ) > offset ) {
    uint16_t data_length = ( uint16_t ) ( ntohs( dst->len ) - offset );
    memmove( ( char * ) dst + offset, ( const char * ) src + offset, data_length );
  }
}


void
ntoh_action_mpls_ttl( struct ofp_action_mpls_ttl *dst, const struct ofp_action_mpls_ttl *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->mpls_ttl = src->mpls_ttl;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_action_push( struct ofp_action_push *dst, const struct ofp_action_push *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->ethertype = ntohs( src->ethertype );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_action_pop_mpls( struct ofp_action_pop_mpls *dst, const struct ofp_action_pop_mpls *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->ethertype = ntohs( src->ethertype );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_action_group( struct ofp_action_group *dst, const struct ofp_action_group *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->group_id = ntohl( src->group_id );
}


void
ntoh_action_nw_ttl( struct ofp_action_nw_ttl *dst, const struct ofp_action_nw_ttl *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->nw_ttl = src->nw_ttl;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_action_header( struct ofp_action_header *dst, const struct ofp_action_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_action( struct ofp_action_header *dst, const struct ofp_action_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( ntohs( src->type ) ) {
    case OFPAT_OUTPUT:
    {
      ntoh_action_output( ( struct ofp_action_output * ) dst, ( const struct ofp_action_output * ) src );
    }
    break;

    case OFPAT_COPY_TTL_OUT:
    case OFPAT_COPY_TTL_IN:
    case OFPAT_DEC_MPLS_TTL:
    case OFPAT_POP_VLAN:
    case OFPAT_POP_PBB:
    case OFPAT_DEC_NW_TTL:
    {
      ntoh_action_header( dst, src );
    }
    break;

    case OFPAT_SET_MPLS_TTL:
    {
      ntoh_action_mpls_ttl( ( struct ofp_action_mpls_ttl * ) dst, ( const struct ofp_action_mpls_ttl * ) src );
    }
    break;

    case OFPAT_PUSH_VLAN:
    case OFPAT_PUSH_MPLS:
    case OFPAT_PUSH_PBB:
    {
      ntoh_action_push( ( struct ofp_action_push * ) dst, ( const struct ofp_action_push * ) src );
    }
    break;

    case OFPAT_POP_MPLS:
    {
      ntoh_action_pop_mpls( ( struct ofp_action_pop_mpls * ) dst, ( const struct ofp_action_pop_mpls * ) src );
    }
    break;

    case OFPAT_SET_QUEUE:
    {
      ntoh_action_set_queue( ( struct ofp_action_set_queue * ) dst, ( const struct ofp_action_set_queue * ) src );
    }
    break;

    case OFPAT_GROUP:
    {
      ntoh_action_group( ( struct ofp_action_group * ) dst, ( const struct ofp_action_group * ) src );
    }
    break;

    case OFPAT_SET_NW_TTL:
    {
      ntoh_action_nw_ttl( ( struct ofp_action_nw_ttl * ) dst, ( const struct ofp_action_nw_ttl * ) src );
    }
    break;

    case OFPAT_SET_FIELD:
    {
      ntoh_action_set_field( ( struct ofp_action_set_field * ) dst, ( const struct ofp_action_set_field * ) src );
    }
    break;

    case OFPAT_EXPERIMENTER:
    {
      ntoh_action_experimenter( ( struct ofp_action_experimenter_header * ) dst, ( const struct ofp_action_experimenter_header * ) src );
    }
    break;

    default:
    {
      die( "Undefined action type ( type = %#x ).", ntohs( src->type ) );
    }
    break;
  }
}


void
hton_action( struct ofp_action_header *dst, const struct ofp_action_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( src->type ) {
    case OFPAT_OUTPUT:
    {
      hton_action_output( ( struct ofp_action_output * ) dst, ( const struct ofp_action_output * ) src );
    }
    break;

    case OFPAT_COPY_TTL_OUT:
    case OFPAT_COPY_TTL_IN:
    case OFPAT_DEC_MPLS_TTL:
    case OFPAT_POP_VLAN:
    case OFPAT_POP_PBB:
    case OFPAT_DEC_NW_TTL:
    {
      hton_action_header( dst, src );
    }
    break;

    case OFPAT_SET_MPLS_TTL:
    {
      hton_action_mpls_ttl( ( struct ofp_action_mpls_ttl * ) dst, ( const struct ofp_action_mpls_ttl * ) src );
    }
    break;

    case OFPAT_PUSH_VLAN:
    case OFPAT_PUSH_MPLS:
    case OFPAT_PUSH_PBB:
    {
      hton_action_push( ( struct ofp_action_push * ) dst, ( const struct ofp_action_push * ) src );
    }
    break;

    case OFPAT_POP_MPLS:
    {
      hton_action_pop_mpls( ( struct ofp_action_pop_mpls * ) dst, ( const struct ofp_action_pop_mpls * ) src );
    }
    break;

    case OFPAT_SET_QUEUE:
    {
      hton_action_set_queue( ( struct ofp_action_set_queue * ) dst, ( const struct ofp_action_set_queue * ) src );
    }
    break;

    case OFPAT_GROUP:
    {
      hton_action_group( ( struct ofp_action_group * ) dst, ( const struct ofp_action_group * ) src );
    }
    break;

    case OFPAT_SET_NW_TTL:
    {
      hton_action_nw_ttl( ( struct ofp_action_nw_ttl * ) dst, ( const struct ofp_action_nw_ttl * ) src );
    }
    break;

    case OFPAT_SET_FIELD:
    {
      hton_action_set_field( ( struct ofp_action_set_field * ) dst, ( const struct ofp_action_set_field * ) src );
    }
    break;

    case OFPAT_EXPERIMENTER:
    {
      hton_action_experimenter( ( struct ofp_action_experimenter_header * ) dst, ( const struct ofp_action_experimenter_header * ) src );
    }
    break;

    default:
    {
      die( "Undefined action type ( type = %#x ).", src->type );
    }
    break;
  }
}


void
ntoh_flow_stats( struct ofp_flow_stats *dst, const struct ofp_flow_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->length = ntohs( src->length );
  dst->table_id = src->table_id;
  dst->pad = 0;
  dst->duration_sec = ntohl( src->duration_sec );
  dst->duration_nsec = ntohl( src->duration_nsec );
  dst->priority = ntohs( src->priority );
  dst->idle_timeout = ntohs( src->idle_timeout );
  dst->hard_timeout = ntohs( src->hard_timeout );
  dst->flags = ntohs( src->flags );
  memset( &dst->pad2, 0, sizeof( dst->pad2 ) );
  dst->cookie = ntohll( src->cookie );
  dst->packet_count = ntohll( src->packet_count );
  dst->byte_count = ntohll( src->byte_count );
  ntoh_match( &dst->match, &src->match );

  uint16_t match_length = ( uint16_t ) ( dst->match.length + PADLEN_TO_64( dst->match.length ) );
  size_t offset = offsetof( struct ofp_flow_stats, match ) + match_length;
  size_t instructions_length = dst->length - offset;

  while ( instructions_length > sizeof( struct ofp_instruction ) ) {
    const struct ofp_instruction *inst_src = ( const struct ofp_instruction * ) ( ( const char * ) src + offset );
    struct ofp_instruction *inst_dst = ( struct ofp_instruction * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( inst_src->len );
    if ( instructions_length < part_length ) {
      break;
    }
    ntoh_instruction( inst_dst, inst_src );

    instructions_length -= part_length;
    offset += part_length;
  }
}


void
hton_flow_stats( struct ofp_flow_stats *dst, const struct ofp_flow_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->length = htons( src->length );
  dst->table_id = src->table_id;
  dst->pad = 0;
  dst->duration_sec = htonl( src->duration_sec );
  dst->duration_nsec = htonl( src->duration_nsec );
  dst->priority = htons( src->priority );
  dst->idle_timeout = htons( src->idle_timeout );
  dst->hard_timeout = htons( src->hard_timeout );
  dst->flags = htons( src->flags );
  memset( &dst->pad2, 0, sizeof( dst->pad2 ) );
  dst->cookie = htonll( src->cookie );
  dst->packet_count = htonll( src->packet_count );
  dst->byte_count = htonll( src->byte_count );
  hton_match( &dst->match, &src->match );

  uint16_t match_length = ( uint16_t ) ( ntohs( dst->match.length ) + PADLEN_TO_64( ntohs( dst->match.length ) ) );
  size_t offset = offsetof( struct ofp_flow_stats, match ) + match_length;
  size_t instructions_length = ntohs( dst->length ) - offset;

  while ( instructions_length > sizeof( struct ofp_instruction ) ) {
    const struct ofp_instruction *inst_src = ( const struct ofp_instruction * ) ( ( const char * ) src + offset );
    struct ofp_instruction *inst_dst = ( struct ofp_instruction * ) ( ( char * ) dst + offset );

    uint16_t part_length = inst_src->len;
    if ( instructions_length < part_length ) {
        break;
    }
    hton_instruction( inst_dst, inst_src );

    instructions_length -= part_length;
    offset += part_length;
  }
}


void
ntoh_aggregate_stats( struct ofp_aggregate_stats_reply *dst, const struct ofp_aggregate_stats_reply *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->packet_count = ntohll( src->packet_count );
  dst->byte_count = ntohll( src->byte_count );
  dst->flow_count = ntohl( src->flow_count );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_table_stats( struct ofp_table_stats *dst, const struct ofp_table_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->table_id = src->table_id;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->active_count = ntohl( src->active_count );
  dst->lookup_count = ntohll( src->lookup_count );
  dst->matched_count = ntohll( src->matched_count );
}


void
ntoh_port_stats( struct ofp_port_stats *dst, const struct ofp_port_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->port_no = ntohl( src->port_no );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->rx_packets = ntohll( src->rx_packets );
  dst->tx_packets = ntohll( src->tx_packets );
  dst->rx_bytes = ntohll( src->rx_bytes );
  dst->tx_bytes = ntohll( src->tx_bytes );
  dst->rx_dropped = ntohll( src->rx_dropped );
  dst->tx_dropped = ntohll( src->tx_dropped );
  dst->rx_errors = ntohll( src->rx_errors );
  dst->tx_errors = ntohll( src->tx_errors );
  dst->rx_frame_err = ntohll( src->rx_frame_err );
  dst->rx_over_err = ntohll( src->rx_over_err );
  dst->rx_crc_err = ntohll( src->rx_crc_err );
  dst->collisions = ntohll( src->collisions );
  dst->duration_sec = ntohl( src->duration_sec );
  dst->duration_nsec = ntohl( src->duration_nsec );
}


void
ntoh_queue_stats( struct ofp_queue_stats *dst, const struct ofp_queue_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->port_no = ntohl( src->port_no );
  dst->queue_id = ntohl( src->queue_id );
  dst->tx_bytes = ntohll( src->tx_bytes );
  dst->tx_packets = ntohll( src->tx_packets );
  dst->tx_errors = ntohll( src->tx_errors );
  dst->duration_sec = ntohl( src->duration_sec );
  dst->duration_nsec = ntohl( src->duration_nsec );
}


void
ntoh_queue_property( struct ofp_queue_prop_header *dst, const struct ofp_queue_prop_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->len ) != 0 );

  dst->property = ntohs( src->property );
  dst->len = ntohs( src->len );
  
  if ( dst->property == OFPQT_MIN_RATE ) {
    const struct ofp_queue_prop_min_rate *mr_src = ( const struct ofp_queue_prop_min_rate * ) src;
    struct ofp_queue_prop_min_rate *mr_dst = ( struct ofp_queue_prop_min_rate * ) dst;

    mr_dst->rate = ntohs( mr_src->rate );
  }
  else if ( dst->property == OFPQT_MAX_RATE ) {
    const struct ofp_queue_prop_max_rate *mr_src = ( const struct ofp_queue_prop_max_rate * ) src;
    struct ofp_queue_prop_max_rate *mr_dst = ( struct ofp_queue_prop_max_rate * ) dst;

    mr_dst->rate = ntohs( mr_src->rate );
  }
  else if ( dst->property == OFPQT_EXPERIMENTER ) {
    const struct ofp_queue_prop_experimenter *exp_src = ( const struct ofp_queue_prop_experimenter * ) src;
    struct ofp_queue_prop_experimenter *exp_dst = ( struct ofp_queue_prop_experimenter * ) dst;

    exp_dst->experimenter = ntohl( exp_src->experimenter );

    uint16_t offset = offsetof( struct ofp_queue_prop_experimenter, data );
    if ( dst->len > offset ) {
      uint16_t data_length = ( uint16_t ) ( dst->len - offset );
      memmove( exp_dst->data, exp_src->data, data_length );
    }
  }
}


void
hton_queue_property( struct ofp_queue_prop_header *dst, const struct ofp_queue_prop_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->len != 0 );

  dst->property = htons( src->property );
  dst->len = htons( src->len );
  
  if ( src->property == OFPQT_MIN_RATE ) {
    const struct ofp_queue_prop_min_rate *mr_src = ( const struct ofp_queue_prop_min_rate * ) src;
    struct ofp_queue_prop_min_rate *mr_dst = ( struct ofp_queue_prop_min_rate * ) dst;

    mr_dst->rate = htons( mr_src->rate );
  }
  else if ( src->property == OFPQT_MAX_RATE ) {
    const struct ofp_queue_prop_max_rate *mr_src = ( const struct ofp_queue_prop_max_rate * ) src;
    struct ofp_queue_prop_max_rate *mr_dst = ( struct ofp_queue_prop_max_rate * ) dst;

    mr_dst->rate = htons( mr_src->rate );
  }
  else if ( src->property == OFPQT_EXPERIMENTER ) {
    const struct ofp_queue_prop_experimenter *exp_src = ( const struct ofp_queue_prop_experimenter * ) src;
    struct ofp_queue_prop_experimenter *exp_dst = ( struct ofp_queue_prop_experimenter * ) dst;

    exp_dst->experimenter = htonl( exp_src->experimenter );

    uint16_t offset = offsetof( struct ofp_queue_prop_experimenter, data );
    if ( ntohs( dst->len ) > offset ) {
      uint16_t data_length = ( uint16_t ) ( ntohs( dst->len ) - offset );
      memmove( exp_dst->data, exp_src->data, data_length );
    }
  }
}


void
ntoh_packet_queue( struct ofp_packet_queue *dst, const struct ofp_packet_queue *src ) {
  /* Note that ofp_packet_queue is variable length.
   * Please make sure that dst and src have the same length.
   */
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->len ) != 0 );

  dst->queue_id = ntohl( src->queue_id );
  dst->port = ntohl( src->port );
  dst->len = ntohs( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  size_t offset = offsetof( struct ofp_packet_queue, properties );
  size_t properties_length = dst->len - offset;

  while ( properties_length >= sizeof( struct ofp_queue_prop_header ) ) {
    const struct ofp_queue_prop_header *ph_src = ( const struct ofp_queue_prop_header * ) ( ( const char * ) src + offset );
    struct ofp_queue_prop_header *ph_dst = ( struct ofp_queue_prop_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( ph_src->len );
    if ( properties_length < part_length ) {
      break;
    }
    ntoh_queue_property( ph_dst, ph_src );

    properties_length -= part_length;
    offset += part_length;
  }
}


void
hton_packet_queue( struct ofp_packet_queue *dst, const struct ofp_packet_queue *src ) {
  /* Note that ofp_packet_queue is variable length.
   * Please make sure that dst and src have the same length.
   */
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->len != 0 );

  dst->queue_id = htonl( src->queue_id );
  dst->port = htonl( src->port );
  dst->len = htons( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  size_t offset = offsetof( struct ofp_packet_queue, properties );
  size_t properties_length = ntohs( dst->len ) - offset;

  while ( properties_length >= sizeof( struct ofp_queue_prop_header ) ) {
    const struct ofp_queue_prop_header *ph_src = ( const struct ofp_queue_prop_header * ) ( ( const char * ) src + offset );
    struct ofp_queue_prop_header *ph_dst = ( struct ofp_queue_prop_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ph_src->len;
    if ( properties_length < part_length ) {
      break;
    }
    hton_queue_property( ph_dst, ph_src );

    properties_length -= part_length;
    offset += part_length;
  }
}


void
ntoh_instruction( struct ofp_instruction *dst, const struct ofp_instruction *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->type ) <= OFPIT_METER || ntohs( src->type ) == OFPIT_EXPERIMENTER );

  if ( ntohs( src->len ) == sizeof( struct ofp_instruction ) ) {
    dst->type = ntohs( src->type );
    dst->len = ntohs( src->len );
    return;
  }

  switch ( ntohs( src->type ) ) {
    case OFPIT_GOTO_TABLE:
    {
      ntoh_instruction_goto_table( ( struct ofp_instruction_goto_table * ) dst, ( const struct ofp_instruction_goto_table * ) src );
    }
    break;

    case OFPIT_WRITE_METADATA:
    {
      ntoh_instruction_write_metadata( ( struct ofp_instruction_write_metadata * ) dst, ( const struct ofp_instruction_write_metadata * ) src );
    }
    break;

    case OFPIT_WRITE_ACTIONS:
    case OFPIT_APPLY_ACTIONS:
    case OFPIT_CLEAR_ACTIONS:
    {
      ntoh_instruction_actions( ( struct ofp_instruction_actions * ) dst, ( const struct ofp_instruction_actions * ) src );
    }
    break;

    case OFPIT_METER:
    {
      ntoh_instruction_meter( ( struct ofp_instruction_meter * ) dst, ( const struct ofp_instruction_meter * ) src );
    }
    break;

    case OFPIT_EXPERIMENTER:
    {
      ntoh_instruction_experimenter( ( struct ofp_instruction_experimenter * ) dst, ( const struct ofp_instruction_experimenter * ) src );
    }
    break;

    default:
    {
      die( "Undefined instruction type ( type = %#x ).", ntohs( src->type ) );
    }
    break;
  }
}


void
hton_instruction( struct ofp_instruction *dst, const struct ofp_instruction *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->type <= OFPIT_METER || src->type == OFPIT_EXPERIMENTER );

  if ( src->len == sizeof( struct ofp_instruction ) ) {
    dst->type = htons( src->type );
    dst->len = htons( src->len );
    return;
  }

  switch ( src->type ) {
    case OFPIT_GOTO_TABLE:
    {
      hton_instruction_goto_table( ( struct ofp_instruction_goto_table * ) dst, ( const struct ofp_instruction_goto_table * ) src );
    }
    break;

    case OFPIT_WRITE_METADATA:
    {
      hton_instruction_write_metadata( ( struct ofp_instruction_write_metadata * ) dst, ( const struct ofp_instruction_write_metadata * ) src );
    }
    break;

    case OFPIT_WRITE_ACTIONS:
    case OFPIT_APPLY_ACTIONS:
    case OFPIT_CLEAR_ACTIONS:
    {
      hton_instruction_actions( ( struct ofp_instruction_actions * ) dst, ( const struct ofp_instruction_actions * ) src );
    }
    break;

    case OFPIT_METER:
    {
      hton_instruction_meter( ( struct ofp_instruction_meter * ) dst, ( const struct ofp_instruction_meter * ) src );
    }
    break;

    case OFPIT_EXPERIMENTER:
    {
      hton_instruction_experimenter( ( struct ofp_instruction_experimenter * ) dst, ( const struct ofp_instruction_experimenter * ) src );
    }
    break;

    default:
    {
      die( "Undefined instruction type ( type = %#x ).", src->type );
    }
    break;
  }
}


void
ntoh_instruction_goto_table( struct ofp_instruction_goto_table *dst, const struct ofp_instruction_goto_table *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->table_id = src->table_id;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void
ntoh_instruction_write_metadata( struct ofp_instruction_write_metadata *dst, const struct ofp_instruction_write_metadata *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->metadata = ntohll( src->metadata );
  dst->metadata_mask = ntohll( src->metadata_mask );
}


void
ntoh_instruction_actions( struct ofp_instruction_actions *dst, const struct ofp_instruction_actions *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->len ) != 0 );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  size_t offset = offsetof( struct ofp_instruction_actions, actions );
  size_t actions_length = dst->len - offset;

  while ( actions_length >= sizeof( struct ofp_action_header ) ) {
    const struct ofp_action_header *ah_src = ( const struct ofp_action_header * ) ( ( const char * ) src + offset );
    struct ofp_action_header *ah_dst = ( struct ofp_action_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( ah_src->len );
    if ( actions_length < part_length ) {
      break;
    }
    ntoh_action( ah_dst, ah_src );

    actions_length -= part_length;
    offset += part_length;
  }
}


void
hton_instruction_actions( struct ofp_instruction_actions *dst, const struct ofp_instruction_actions *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->len != 0 );

  dst->type = htons( src->type );
  dst->len = htons( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  size_t offset = offsetof( struct ofp_instruction_actions, actions );
  size_t actions_length = ntohs( dst->len ) - offset;

  while ( actions_length >= sizeof( struct ofp_action_header ) ) {
    const struct ofp_action_header *ah_src = ( const struct ofp_action_header * ) ( ( const char * ) src + offset );
    struct ofp_action_header *ah_dst = ( struct ofp_action_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ah_src->len;
    if ( actions_length < part_length ) {
      break;
    }
    hton_action( ah_dst, ah_src );

    actions_length -= part_length;
    offset += part_length;
  }
}


void
ntoh_instruction_meter( struct ofp_instruction_meter *dst, const struct ofp_instruction_meter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->meter_id = ntohl( src->meter_id );
}


void
ntoh_instruction_experimenter( struct ofp_instruction_experimenter *dst, const struct ofp_instruction_experimenter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->experimenter = ntohl( src->experimenter );

  uint16_t offset = sizeof( struct ofp_instruction_experimenter );
  if ( dst->len > offset ) {
    uint16_t data_length = ( uint16_t ) ( dst->len - offset );
    memmove( ( char * ) dst + offset, ( const char * ) src + offset, data_length );
  }
}


void
hton_instruction_experimenter( struct ofp_instruction_experimenter *dst, const struct ofp_instruction_experimenter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = htons( src->type );
  dst->len = htons( src->len );
  dst->experimenter = htonl( src->experimenter );

  uint16_t offset = sizeof( struct ofp_instruction_experimenter );
  if ( ntohs( dst->len ) > offset ) {
    uint16_t data_length = ( uint16_t ) ( ntohs( dst->len ) - offset );
    memmove( ( char * ) dst + offset, ( const char * ) src + offset, data_length );
  }
}


void ntoh_bucket( struct ofp_bucket *dst, const struct ofp_bucket *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->len ) != 0 );

  dst->len = ntohs( src->len );
  dst->weight = ntohs( src->weight );
  dst->watch_port = ntohl( src->watch_port );
  dst->watch_group = ntohl( src->watch_group );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  size_t offset = offsetof( struct ofp_bucket, actions );
  size_t actions_length = dst->len - offset;

  while ( actions_length >= sizeof( struct ofp_action_header ) ) {
    const struct ofp_action_header *ah_src = ( const struct ofp_action_header * ) ( ( const char * ) src + offset );
    struct ofp_action_header *ah_dst = ( struct ofp_action_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( ah_src->len );
    if ( actions_length < part_length ) {
      break;
    }
    ntoh_action( ah_dst, ah_src );

    actions_length -= part_length;
    offset += part_length;
  }
}


void hton_bucket( struct ofp_bucket *dst, const struct ofp_bucket *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->len != 0 );

  dst->len = htons( src->len );
  dst->weight = htons( src->weight );
  dst->watch_port = htonl( src->watch_port );
  dst->watch_group = htonl( src->watch_group );
  memset( &dst->pad, 0, sizeof( dst->pad ) );

  size_t offset = offsetof( struct ofp_bucket, actions );
  size_t actions_length = ntohs( dst->len ) - offset;

  while ( actions_length >= sizeof( struct ofp_action_header ) ) {
    const struct ofp_action_header *ah_src = ( const struct ofp_action_header * ) ( ( const char * ) src + offset );
    struct ofp_action_header *ah_dst = ( struct ofp_action_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ah_src->len;
    if ( actions_length < part_length ) {
      break;
    }
    hton_action( ah_dst, ah_src );

    actions_length -= part_length;
    offset += part_length;
  }
}


void ntoh_meter_band_drop( struct ofp_meter_band_drop *dst, const struct ofp_meter_band_drop *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->rate = ntohl( src->rate );
  dst->burst_size = ntohl( src->burst_size );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void ntoh_meter_band_dscp_remark( struct ofp_meter_band_dscp_remark *dst, const struct ofp_meter_band_dscp_remark *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->rate = ntohl( src->rate );
  dst->burst_size = ntohl( src->burst_size );
  dst->prec_level = src->prec_level;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


void ntoh_meter_band_experimenter( struct ofp_meter_band_experimenter *dst, const struct ofp_meter_band_experimenter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->len = ntohs( src->len );
  dst->rate = ntohl( src->rate );
  dst->burst_size = ntohl( src->burst_size );
  dst->experimenter = ntohl( src->experimenter );

  uint16_t offset = sizeof( struct ofp_meter_band_experimenter );
  if ( dst->len > offset ) {
    uint16_t data_length = ( uint16_t ) ( dst->len - offset );
    memmove( ( char * ) dst + offset, ( const char * ) src + offset, data_length );
  }
}


void hton_meter_band_experimenter( struct ofp_meter_band_experimenter *dst, const struct ofp_meter_band_experimenter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = htons( src->type );
  dst->len = htons( src->len );
  dst->rate = htonl( src->rate );
  dst->burst_size = htonl( src->burst_size );
  dst->experimenter = htonl( src->experimenter );

  uint16_t offset = sizeof( struct ofp_meter_band_experimenter );
  if ( ntohs( dst->len ) > offset ) {
    uint16_t data_length = ( uint16_t ) ( ntohs( dst->len ) - offset );
    memmove( ( char * ) dst + offset, ( const char * ) src + offset, data_length );
  }
}


void ntoh_meter_band_header( struct ofp_meter_band_header *dst, const struct ofp_meter_band_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( ntohs( src->type ) ) {
    case OFPMBT_DROP:
    {
      ntoh_meter_band_drop( ( struct ofp_meter_band_drop * ) dst, ( const struct ofp_meter_band_drop * ) src );
    }
    break;

    case OFPMBT_DSCP_REMARK:
    {
      ntoh_meter_band_dscp_remark( ( struct ofp_meter_band_dscp_remark * ) dst, ( const struct ofp_meter_band_dscp_remark * ) src );
    }
    break;

    case OFPMBT_EXPERIMENTER:
    {
      ntoh_meter_band_experimenter( ( struct ofp_meter_band_experimenter * ) dst, ( const struct ofp_meter_band_experimenter * ) src );
    }
    break;

    default:
    {
      die( "Undefined meter band type ( type = %#x ).", ntohs( src->type ) );
    }
    break;
  }
}


void hton_meter_band_header( struct ofp_meter_band_header *dst, const struct ofp_meter_band_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( src->type ) {
    case OFPMBT_DROP:
    {
      hton_meter_band_drop( ( struct ofp_meter_band_drop * ) dst, ( const struct ofp_meter_band_drop * ) src );
    }
    break;

    case OFPMBT_DSCP_REMARK:
    {
      hton_meter_band_dscp_remark( ( struct ofp_meter_band_dscp_remark * ) dst, ( const struct ofp_meter_band_dscp_remark * ) src );
    }
    break;

    case OFPMBT_EXPERIMENTER:
    {
      hton_meter_band_experimenter( ( struct ofp_meter_band_experimenter * ) dst, ( const struct ofp_meter_band_experimenter * ) src );
    }
    break;

    default:
    {
      die( "Undefined meter band type ( type = %#x ).", src->type );
    }
    break;
  }
}


void ntoh_table_feature_prop_instructions( struct ofp_table_feature_prop_instructions *dst, const struct ofp_table_feature_prop_instructions *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->type = ntohs( src->type );
  dst->length = ntohs( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_instructions, instruction_ids );
  size_t instructions_length = dst->length - offset;

  while ( instructions_length >= sizeof( struct ofp_instruction ) ) {
    const struct ofp_instruction *inst_src = ( const struct ofp_instruction * ) ( ( const char * ) src + offset );
    struct ofp_instruction *inst_dst = ( struct ofp_instruction * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( inst_src->len );
    if ( instructions_length < part_length ) {
      break;
    }
    ntoh_instruction( inst_dst, inst_src );

    instructions_length -= part_length;
    offset += part_length;
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( dst->length );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + dst->length, 0, padding_length );
  }
}


void hton_table_feature_prop_instructions( struct ofp_table_feature_prop_instructions *dst, const struct ofp_table_feature_prop_instructions *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->type = htons( src->type );
  dst->length = htons( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_instructions, instruction_ids );
  size_t instructions_length = ntohs( dst->length ) - offset;

  while ( instructions_length >= sizeof( struct ofp_instruction ) ) {
    const struct ofp_instruction *inst_src = ( const struct ofp_instruction * ) ( ( const char * ) src + offset );
    struct ofp_instruction *inst_dst = ( struct ofp_instruction * ) ( ( char * ) dst + offset );

    uint16_t part_length = inst_src->len;
    if ( instructions_length < part_length ) {
      break;
    }
    hton_instruction( inst_dst, inst_src );

    instructions_length -= part_length;
    offset += part_length;
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( ntohs( dst->length ) );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + ntohs( dst->length ), 0, padding_length );
  }
}


void ntoh_table_feature_prop_next_tables( struct ofp_table_feature_prop_next_tables *dst, const struct ofp_table_feature_prop_next_tables *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->type = ntohs( src->type );
  dst->length = ntohs( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_next_tables, next_table_ids );
  size_t table_length = dst->length - offset;
  memmove( ( char * ) dst + offset, ( const char * ) src + offset, table_length );
  size_t padding_length = ( size_t ) PADLEN_TO_64( dst->length );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + dst->length, 0, padding_length );
  }
}


void hton_table_feature_prop_next_tables( struct ofp_table_feature_prop_next_tables *dst, const struct ofp_table_feature_prop_next_tables *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->type = htons( src->type );
  dst->length = htons( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_next_tables, next_table_ids );
  size_t table_length = ntohs( dst->length ) - offset;
  memmove( ( char * ) dst + offset, ( const char * ) src + offset, table_length );
  size_t padding_length = ( size_t ) PADLEN_TO_64( ntohs( dst->length ) );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + ntohs( dst->length ), 0, padding_length );
  }
}


void ntoh_table_feature_prop_actions( struct ofp_table_feature_prop_actions *dst, const struct ofp_table_feature_prop_actions *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->type = ntohs( src->type );
  dst->length = ntohs( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_actions, action_ids );
  size_t actions_length = dst->length - offset;

  while ( actions_length >= sizeof( struct ofp_action_header ) ) {
    const struct ofp_action_header *act_src = ( const struct ofp_action_header * ) ( ( const char * ) src + offset );
    struct ofp_action_header *act_dst = ( struct ofp_action_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( act_src->len );
    if ( actions_length < part_length ) {
      break;
    }
    ntoh_action( act_dst, act_src );

    actions_length -= part_length;
    offset += part_length;
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( dst->length );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + dst->length, 0, padding_length );
  }
}


void hton_table_feature_prop_actions( struct ofp_table_feature_prop_actions *dst, const struct ofp_table_feature_prop_actions *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->type = htons( src->type );
  dst->length = htons( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_actions, action_ids );
  size_t actions_length = ntohs( dst->length ) - offset;

  while ( actions_length >= sizeof( struct ofp_action_header ) ) {
    const struct ofp_action_header *act_src = ( const struct ofp_action_header * ) ( ( const char * ) src + offset );
    struct ofp_action_header *act_dst = ( struct ofp_action_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = act_src->len;
    if ( actions_length < part_length ) {
      break;
    }
    hton_action( act_dst, act_src );

    actions_length -= part_length;
    offset += part_length;
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( ntohs( dst->length ) );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + ntohs( dst->length ), 0, padding_length );
  }
}


void ntoh_table_feature_prop_oxm( struct ofp_table_feature_prop_oxm *dst, const struct ofp_table_feature_prop_oxm *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->type = ntohs( src->type );
  dst->length = ntohs( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_oxm, oxm_ids );
  size_t oxm_length = dst->length - offset;

  int i = 0;
  while ( oxm_length >= sizeof( uint32_t ) ) {
    dst->oxm_ids[ i ] = ntohl( src->oxm_ids[ i ] );
    oxm_length -= sizeof( uint32_t );
    i++;
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( dst->length );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + dst->length, 0, padding_length );
  }
}


void hton_table_feature_prop_oxm( struct ofp_table_feature_prop_oxm *dst, const struct ofp_table_feature_prop_oxm *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->type = htons( src->type );
  dst->length = htons( src->length );

  size_t offset = offsetof( struct ofp_table_feature_prop_oxm, oxm_ids );
  size_t oxm_length = ntohs( dst->length ) - offset;

  int i = 0;
  while ( oxm_length >= sizeof( uint32_t ) ) {
    dst->oxm_ids[ i ] = htonl( src->oxm_ids[ i ] );
    oxm_length -= sizeof( uint32_t );
    i++;
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( ntohs( dst->length ) );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + ntohs( dst->length ), 0, padding_length );
  }
}


void ntoh_table_feature_prop_experimenter( struct ofp_table_feature_prop_experimenter *dst, const struct ofp_table_feature_prop_experimenter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = ntohs( src->type );
  dst->length = ntohs( src->length );
  dst->experimenter = ntohl( src->experimenter );
  dst->exp_type = ntohl( src->exp_type );

  uint16_t offset = offsetof( struct ofp_table_feature_prop_experimenter, experimenter_data );
  if ( dst->length > offset ) {
    uint16_t data_length = ( uint16_t ) ( dst->length - offset );
    memmove( dst->experimenter_data, src->experimenter_data, data_length );
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( dst->length );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + dst->length, 0, padding_length );
  }
}


void hton_table_feature_prop_experimenter( struct ofp_table_feature_prop_experimenter *dst, const struct ofp_table_feature_prop_experimenter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->type = htons( src->type );
  dst->length = htons( src->length );
  dst->experimenter = htonl( src->experimenter );
  dst->exp_type = htonl( src->exp_type );

  uint16_t offset = offsetof( struct ofp_table_feature_prop_experimenter, experimenter_data );
  if ( ntohs( dst->length ) > offset ) {
    uint16_t data_length = ( uint16_t ) ( ntohs( dst->length ) - offset );
    memmove( dst->experimenter_data, src->experimenter_data, data_length );
  }

  size_t padding_length = ( size_t ) PADLEN_TO_64( ntohs( dst->length ) );
  if ( padding_length > 0 ) {
    memset( ( char * ) dst + ntohs( dst->length ), 0, padding_length );
  }
}


void ntoh_table_feature_prop_header( struct ofp_table_feature_prop_header *dst, const struct ofp_table_feature_prop_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( ntohs( src->type ) ) {
    case OFPTFPT_INSTRUCTIONS:
    case OFPTFPT_INSTRUCTIONS_MISS:
    {
      ntoh_table_feature_prop_instructions( ( struct ofp_table_feature_prop_instructions * ) dst, ( const struct ofp_table_feature_prop_instructions * ) src );
    }
    break;

    case OFPTFPT_NEXT_TABLES:
    case OFPTFPT_NEXT_TABLES_MISS:
    {
      ntoh_table_feature_prop_next_tables( ( struct ofp_table_feature_prop_next_tables * ) dst, ( const struct ofp_table_feature_prop_next_tables * ) src );
    }
    break;

    case OFPTFPT_WRITE_ACTIONS:
    case OFPTFPT_WRITE_ACTIONS_MISS:
    case OFPTFPT_APPLY_ACTIONS:
    case OFPTFPT_APPLY_ACTIONS_MISS:
    {
      ntoh_table_feature_prop_actions( ( struct ofp_table_feature_prop_actions * ) dst, ( const struct ofp_table_feature_prop_actions * ) src );
    }
    break;

    case OFPTFPT_MATCH:
    case OFPTFPT_WILDCARDS:
    case OFPTFPT_WRITE_SETFIELD:
    case OFPTFPT_WRITE_SETFIELD_MISS:
    case OFPTFPT_APPLY_SETFIELD:
    case OFPTFPT_APPLY_SETFIELD_MISS:
    {
      ntoh_table_feature_prop_oxm( ( struct ofp_table_feature_prop_oxm * ) dst, ( const struct ofp_table_feature_prop_oxm * ) src );
    }
    break;

    case OFPTFPT_EXPERIMENTER:
    case OFPTFPT_EXPERIMENTER_MISS:
    {
      ntoh_table_feature_prop_experimenter( ( struct ofp_table_feature_prop_experimenter * ) dst, ( const struct ofp_table_feature_prop_experimenter * ) src );
    }
    break;

    default:
    {
      die( "Undefined table feature property type ( type = %#x ).", ntohs( src->type ) );
    }
    break;
  }
}


void hton_table_feature_prop_header( struct ofp_table_feature_prop_header *dst, const struct ofp_table_feature_prop_header *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  switch ( src->type ) {
    case OFPTFPT_INSTRUCTIONS:
    case OFPTFPT_INSTRUCTIONS_MISS:
    {
      hton_table_feature_prop_instructions( ( struct ofp_table_feature_prop_instructions * ) dst, ( const struct ofp_table_feature_prop_instructions * ) src );
    }
    break;

    case OFPTFPT_NEXT_TABLES:
    case OFPTFPT_NEXT_TABLES_MISS:
    {
      hton_table_feature_prop_next_tables( ( struct ofp_table_feature_prop_next_tables * ) dst, ( const struct ofp_table_feature_prop_next_tables * ) src );
    }
    break;

    case OFPTFPT_WRITE_ACTIONS:
    case OFPTFPT_WRITE_ACTIONS_MISS:
    case OFPTFPT_APPLY_ACTIONS:
    case OFPTFPT_APPLY_ACTIONS_MISS:
    {
      hton_table_feature_prop_actions( ( struct ofp_table_feature_prop_actions * ) dst, ( const struct ofp_table_feature_prop_actions * ) src );
    }
    break;

    case OFPTFPT_MATCH:
    case OFPTFPT_WILDCARDS:
    case OFPTFPT_WRITE_SETFIELD:
    case OFPTFPT_WRITE_SETFIELD_MISS:
    case OFPTFPT_APPLY_SETFIELD:
    case OFPTFPT_APPLY_SETFIELD_MISS:
    {
      hton_table_feature_prop_oxm( ( struct ofp_table_feature_prop_oxm * ) dst, ( const struct ofp_table_feature_prop_oxm * ) src );
    }
    break;

    case OFPTFPT_EXPERIMENTER:
    case OFPTFPT_EXPERIMENTER_MISS:
    {
      hton_table_feature_prop_experimenter( ( struct ofp_table_feature_prop_experimenter * ) dst, ( const struct ofp_table_feature_prop_experimenter * ) src );
    }
    break;

    default:
    {
      die( "Undefined table feature property type ( type = %#x ).", src->type );
    }
    break;
  }
}


void ntoh_table_features( struct ofp_table_features *dst, const struct ofp_table_features *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->length = ntohs( src->length );
  dst->table_id = src->table_id;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  memmove( dst->name, src->name, OFP_MAX_TABLE_NAME_LEN );
  dst->metadata_match = ntohll( src->metadata_match );
  dst->metadata_write = ntohll( src->metadata_write );
  dst->config = ntohl( src->config );
  dst->max_entries = ntohl( src->max_entries );

  size_t offset = offsetof( struct ofp_table_features, properties );
  size_t table_features_length = dst->length - offset;

  while ( table_features_length >= sizeof( struct ofp_table_feature_prop_header ) ) {
    const struct ofp_table_feature_prop_header *ph_src = ( const struct ofp_table_feature_prop_header * ) ( ( const char * ) src + offset );
    struct ofp_table_feature_prop_header *ph_dst = ( struct ofp_table_feature_prop_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ( uint16_t ) ( ntohs( ph_src->length ) + PADLEN_TO_64( ntohs( ph_src->length ) ) );
    if ( table_features_length < part_length ) {
      break;
    }
    ntoh_table_feature_prop_header( ph_dst, ph_src );

    table_features_length -= part_length;
    offset += part_length;
  }
}


void hton_table_features( struct ofp_table_features *dst, const struct ofp_table_features *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->length = htons( src->length );
  dst->table_id = src->table_id;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  memmove( dst->name, src->name, OFP_MAX_TABLE_NAME_LEN );
  dst->metadata_match = htonll( src->metadata_match );
  dst->metadata_write = htonll( src->metadata_write );
  dst->config = htonl( src->config );
  dst->max_entries = htonl( src->max_entries );

  size_t offset = offsetof( struct ofp_table_features, properties );
  size_t table_features_length = ntohs( dst->length ) - offset;

  while ( table_features_length >= sizeof( struct ofp_table_feature_prop_header ) ) {
    const struct ofp_table_feature_prop_header *ph_src = ( const struct ofp_table_feature_prop_header * ) ( ( const char * ) src + offset );
    struct ofp_table_feature_prop_header *ph_dst = ( struct ofp_table_feature_prop_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ( uint16_t ) ( ph_src->length + PADLEN_TO_64( ph_src->length ) );
    if ( table_features_length < part_length ) {
      break;
    }
    hton_table_feature_prop_header( ph_dst, ph_src );

    table_features_length -= part_length;
    offset += part_length;
  }
}


void ntoh_bucket_counter( struct ofp_bucket_counter *dst, const struct ofp_bucket_counter *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->packet_count = ntohll( src->packet_count );
  dst->byte_count = ntohll( src->byte_count );
}


void ntoh_group_stats( struct ofp_group_stats *dst, const struct ofp_group_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->length = ntohs( src->length );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->group_id = ntohl( src->group_id );
  dst->ref_count = ntohl( src->ref_count );
  memset( &dst->pad2, 0, sizeof( dst->pad2 ) );
  dst->packet_count = ntohll( src->packet_count );
  dst->byte_count = ntohll( src->byte_count );
  dst->duration_sec = ntohl( src->duration_sec );
  dst->duration_nsec = ntohl( src->duration_nsec );

  size_t offset = offsetof( struct ofp_group_stats, bucket_stats );
  size_t stats_length = dst->length - offset;

  while ( stats_length >= sizeof( struct ofp_bucket_counter ) ) {
    const struct ofp_bucket_counter *bc_src = ( const struct ofp_bucket_counter * ) ( ( const char * ) src + offset );
    struct ofp_bucket_counter *bc_dst = ( struct ofp_bucket_counter * ) ( ( char * ) dst + offset );

    ntoh_bucket_counter( bc_dst, bc_src );

    stats_length -= sizeof( struct ofp_bucket_counter );
    offset += sizeof( struct ofp_bucket_counter );
  }
}


void hton_group_stats( struct ofp_group_stats *dst, const struct ofp_group_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->length = htons( src->length );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->group_id = htonl( src->group_id );
  dst->ref_count = htonl( src->ref_count );
  memset( &dst->pad2, 0, sizeof( dst->pad2 ) );
  dst->packet_count = htonll( src->packet_count );
  dst->byte_count = htonll( src->byte_count );
  dst->duration_sec = htonl( src->duration_sec );
  dst->duration_nsec = htonl( src->duration_nsec );

  size_t offset = offsetof( struct ofp_group_stats, bucket_stats );
  size_t stats_length = ntohs( dst->length ) - offset;

  while ( stats_length >= sizeof( struct ofp_bucket_counter ) ) {
    const struct ofp_bucket_counter *bc_src = ( const struct ofp_bucket_counter * ) ( ( const char * ) src + offset );
    struct ofp_bucket_counter *bc_dst = ( struct ofp_bucket_counter * ) ( ( char * ) dst + offset );

    hton_bucket_counter( bc_dst, bc_src );

    stats_length -= sizeof( struct ofp_bucket_counter );
    offset += sizeof( struct ofp_bucket_counter );
  }
}


void ntoh_group_desc( struct ofp_group_desc *dst, const struct ofp_group_desc *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->length = ntohs( src->length );
  dst->type = src->type;
  dst->pad = 0;
  dst->group_id = ntohl( src->group_id );

  size_t offset = offsetof( struct ofp_group_desc, buckets );
  size_t buckets_length = dst->length - offset;

  while ( buckets_length >= sizeof( struct ofp_bucket ) ) {
    const struct ofp_bucket *bc_src = ( const struct ofp_bucket * ) ( ( const char * ) src + offset );
    struct ofp_bucket *bc_dst = ( struct ofp_bucket * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( bc_src->len );
    if ( buckets_length < part_length ) {
      break;
    }
    ntoh_bucket( bc_dst, bc_src );

    buckets_length -= part_length;
    offset += part_length;
  }
}


void hton_group_desc( struct ofp_group_desc *dst, const struct ofp_group_desc *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->length = htons( src->length );
  dst->type = src->type;
  dst->pad = 0;
  dst->group_id = htonl( src->group_id );

  size_t offset = offsetof( struct ofp_group_desc, buckets );
  size_t buckets_length = ntohs( dst->length ) - offset;

  while ( buckets_length >= sizeof( struct ofp_bucket ) ) {
    const struct ofp_bucket *bc_src = ( const struct ofp_bucket * ) ( ( const char * ) src + offset );
    struct ofp_bucket *bc_dst = ( struct ofp_bucket * ) ( ( char * ) dst + offset );

    uint16_t part_length = bc_src->len;
    if ( buckets_length < part_length ) {
      break;
    }
    hton_bucket( bc_dst, bc_src );

    buckets_length -= part_length;
    offset += part_length;
  }
}


void ntoh_group_features_stats( struct ofp_group_features *dst, const struct ofp_group_features *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->types = ntohl( src->types );
  dst->capabilities = ntohl( src->capabilities );

  for ( int i = 0; i < 4; i++ ) {
    dst->max_groups[ i ] = ntohl( src->max_groups[ i ] );
    dst->actions[ i ] = ntohl( src->actions[ i ] );
  }
}


void ntoh_meter_band_stats( struct ofp_meter_band_stats *dst, const struct ofp_meter_band_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->packet_band_count = ntohll( src->packet_band_count );
  dst->byte_band_count = ntohll( src->byte_band_count );
}


void ntoh_meter_stats( struct ofp_meter_stats *dst, const struct ofp_meter_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->len ) != 0 );

  dst->meter_id = ntohl( src->meter_id );
  dst->len = ntohs( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->flow_count = ntohl( src->flow_count );
  dst->packet_in_count = ntohll( src->packet_in_count );
  dst->byte_in_count = ntohll( src->byte_in_count );
  dst->duration_sec = ntohl( src->duration_sec );
  dst->duration_nsec = ntohl( src->duration_nsec );

  size_t offset = offsetof( struct ofp_meter_stats, band_stats );
  size_t stats_length = dst->len - offset;

  while ( stats_length >= sizeof( struct ofp_meter_band_stats ) ) {
    const struct ofp_meter_band_stats *bs_src = ( const struct ofp_meter_band_stats * ) ( ( const char * ) src + offset );
    struct ofp_meter_band_stats *bs_dst = ( struct ofp_meter_band_stats * ) ( ( char * ) dst + offset );

    ntoh_meter_band_stats( bs_dst, bs_src );

    stats_length -= sizeof( struct ofp_meter_band_stats );
    offset += sizeof( struct ofp_meter_band_stats );
  }
}


void hton_meter_stats( struct ofp_meter_stats *dst, const struct ofp_meter_stats *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->len != 0 );

  dst->meter_id = htonl( src->meter_id );
  dst->len = htons( src->len );
  memset( &dst->pad, 0, sizeof( dst->pad ) );
  dst->flow_count = htonl( src->flow_count );
  dst->packet_in_count = htonll( src->packet_in_count );
  dst->byte_in_count = htonll( src->byte_in_count );
  dst->duration_sec = htonl( src->duration_sec );
  dst->duration_nsec = htonl( src->duration_nsec );

  size_t offset = offsetof( struct ofp_meter_stats, band_stats );
  size_t stats_length = ntohs( dst->len ) - offset;

  while ( stats_length >= sizeof( struct ofp_meter_band_stats ) ) {
    const struct ofp_meter_band_stats *bs_src = ( const struct ofp_meter_band_stats * ) ( ( const char * ) src + offset );
    struct ofp_meter_band_stats *bs_dst = ( struct ofp_meter_band_stats * ) ( ( char * ) dst + offset );

    hton_meter_band_stats( bs_dst, bs_src );

    stats_length -= sizeof( struct ofp_meter_band_stats );
    offset += sizeof( struct ofp_meter_band_stats );
  }
}


void ntoh_meter_config( struct ofp_meter_config *dst, const struct ofp_meter_config *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( ntohs( src->length ) != 0 );

  dst->length = ntohs( src->length );
  dst->flags = ntohs( src->flags );
  dst->meter_id = ntohl( src->meter_id );

  size_t offset = offsetof( struct ofp_meter_config, bands );
  size_t bands_length = dst->length - offset;

  while ( bands_length >= sizeof( struct ofp_meter_band_header ) ) {
    const struct ofp_meter_band_header *bh_src = ( const struct ofp_meter_band_header * ) ( ( const char * ) src + offset );
    struct ofp_meter_band_header *bh_dst = ( struct ofp_meter_band_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = ntohs( bh_src->len );
    if ( bands_length < part_length ) {
      break;
    }

    ntoh_meter_band_header( bh_dst, bh_src );

    bands_length -= part_length;
    offset += part_length;
  }
}


void hton_meter_config( struct ofp_meter_config *dst, const struct ofp_meter_config *src ) {
  assert( src != NULL );
  assert( dst != NULL );
  assert( src->length != 0 );

  dst->length = htons( src->length );
  dst->flags = htons( src->flags );
  dst->meter_id = htonl( src->meter_id );

  size_t offset = offsetof( struct ofp_meter_config, bands );
  size_t bands_length = ntohs( dst->length ) - offset;

  while ( bands_length >= sizeof( struct ofp_meter_band_header ) ) {
    const struct ofp_meter_band_header *bh_src = ( const struct ofp_meter_band_header * ) ( ( const char * ) src + offset );
    struct ofp_meter_band_header *bh_dst = ( struct ofp_meter_band_header * ) ( ( char * ) dst + offset );

    uint16_t part_length = bh_src->len;
    if ( bands_length < part_length ) {
      break;
    }

    ntoh_meter_band_header( bh_dst, bh_src );

    bands_length -= part_length;
    offset += part_length;
  }
}


void ntoh_meter_features( struct ofp_meter_features *dst, const struct ofp_meter_features *src ) {
  assert( src != NULL );
  assert( dst != NULL );

  dst->max_meter = ntohl( src->max_meter );
  dst->band_types = ntohl( src->band_types );
  dst->capabilities = ntohl( src->capabilities );
  dst->max_bands = src->max_bands;
  dst->max_color = src->max_color;
  memset( &dst->pad, 0, sizeof( dst->pad ) );
}


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