src/switch/switch/oxm-helper.c
/*
* 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 "trema.h"
#include "ofdp.h"
#include "oxm-helper.h"
#include "oxm-interface.h"
static void
assign_ipv6_exthdr( const oxm_match_header *hdr, match *match ) {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
if ( *hdr == OXM_OF_IPV6_EXTHDR ) {
MATCH_ATTR_SET( ipv6_exthdr, *value )
}
if ( *hdr == OXM_OF_IPV6_EXTHDR_W ) {
const uint16_t *mask = ( const uint16_t * ) ( ( const char * ) value + sizeof ( uint16_t ) );
MATCH_ATTR_MASK_SET( ipv6_exthdr, *value, *mask )
}
}
static void
assign_tunnel_id( const oxm_match_header *hdr, match *match ) {
const uint64_t *value = ( const uint64_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
if ( *hdr == OXM_OF_TUNNEL_ID ) {
MATCH_ATTR_SET( tunnel_id, *value )
}
if ( *hdr == OXM_OF_TUNNEL_ID_W ) {
const uint64_t *mask = ( const uint64_t * ) ( ( const char * ) value + sizeof ( uint64_t ) );
MATCH_ATTR_MASK_SET( tunnel_id, *value, *mask )
}
}
static void
assign_ipv6_nd_addr( const oxm_match_header *hdr, match *match ) {
const uint8_t *addr = ( const uint8_t * ) hdr + sizeof( oxm_match_header );
if ( *hdr == OXM_OF_IPV6_ND_SLL ) {
MATCH_ARRAY_ATTR_SET( ipv6_nd_sll, addr, ETH_ADDRLEN )
}
if ( *hdr == OXM_OF_IPV6_ND_TLL ) {
MATCH_ARRAY_ATTR_SET( ipv6_nd_tll, addr, ETH_ADDRLEN )
}
}
static void
assign_ipv6_flabel( const oxm_match_header *hdr, match *match ) {
const uint32_t *value = ( const uint32_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
if ( *hdr == OXM_OF_IPV6_FLABEL ) {
MATCH_ATTR_SET( ipv6_flabel, *value );
}
if ( *hdr == OXM_OF_IPV6_FLABEL_W ) {
const uint32_t *mask = ( const uint32_t * ) ( ( const char * ) value + sizeof ( uint32_t ) );
MATCH_ATTR_MASK_SET( ipv6_flabel, *value, *mask );
}
}
static void
assign_ipv6_addr( const oxm_match_header *hdr, match *match ) {
const struct in6_addr *addr = ( const struct in6_addr * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
const struct in6_addr *mask;
if ( *hdr == OXM_OF_IPV6_SRC || *hdr == OXM_OF_IPV6_SRC_W ) {
MATCH_ARRAY_ATTR_SET( ipv6_src, addr->s6_addr, IPV6_ADDRLEN );
if ( *hdr == OXM_OF_IPV6_SRC_W ) {
mask = ( const struct in6_addr * ) ( ( const char * ) addr + sizeof ( struct in6_addr ) );
MATCH_ARRAY_MASK_SET( ipv6_src, mask->s6_addr, IPV6_ADDRLEN );
}
}
if ( *hdr == OXM_OF_IPV6_DST || *hdr == OXM_OF_IPV6_DST_W ) {
MATCH_ARRAY_ATTR_SET( ipv6_dst, addr->s6_addr, IPV6_ADDRLEN );
if ( *hdr == OXM_OF_IPV6_DST_W ) {
mask = ( const struct in6_addr * ) ( ( const char * ) addr + sizeof ( struct in6_addr ) );
MATCH_ARRAY_MASK_SET( ipv6_dst, mask->s6_addr, IPV6_ADDRLEN );
}
}
}
static void
assign_arp_hardware_addr( const oxm_match_header *hdr, match *match ) {
const uint8_t *addr = ( const uint8_t * ) hdr + sizeof( oxm_match_header );
const uint8_t *mask;
if ( *hdr == OXM_OF_ARP_SHA || *hdr == OXM_OF_ARP_SHA_W ) {
MATCH_ARRAY_ATTR_SET( arp_sha, addr, ETH_ADDRLEN )
if ( *hdr == OXM_OF_ARP_SHA_W ) {
mask = addr + ( sizeof ( uint8_t ) * ETH_ADDRLEN );
MATCH_ARRAY_MASK_SET( arp_sha, mask, ETH_ADDRLEN )
}
}
if ( *hdr == OXM_OF_ARP_THA || *hdr == OXM_OF_ARP_THA_W ) {
MATCH_ARRAY_ATTR_SET( arp_tha, addr, ETH_ADDRLEN )
if ( *hdr == OXM_OF_ARP_THA_W ) {
mask = addr + ( sizeof ( uint8_t ) * ETH_ADDRLEN );
MATCH_ARRAY_MASK_SET( arp_tha, mask, ETH_ADDRLEN )
}
}
}
static void
assign_arp_protocol_addr( const oxm_match_header *hdr, match *match ) {
const uint32_t *addr = ( const uint32_t * ) ( ( const uint8_t * ) hdr + sizeof ( oxm_match_header ) );
const uint32_t *mask;
if ( *hdr == OXM_OF_ARP_SPA ) {
MATCH_ATTR_SET( arp_spa, *addr );
}
if ( *hdr == OXM_OF_ARP_SPA_W ) {
mask = ( const uint32_t * ) ( ( const uint8_t * ) addr + sizeof ( uint32_t ) );
MATCH_ATTR_MASK_SET( arp_spa, *addr, *mask );
}
if ( *hdr == OXM_OF_ARP_TPA ) {
MATCH_ATTR_SET( arp_tpa, *addr )
}
if ( *hdr == OXM_OF_ARP_TPA_W ) {
mask = ( const uint32_t * ) ( ( const uint8_t * ) addr + sizeof ( uint32_t ) );
MATCH_ATTR_MASK_SET( arp_tpa, *addr, *mask )
}
}
static void
assign_sctp_port( const oxm_match_header *hdr, match *match ) {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
if ( *hdr == OXM_OF_SCTP_SRC ) {
MATCH_ATTR_SET( sctp_src, *value )
}
if ( *hdr == OXM_OF_SCTP_DST ) {
MATCH_ATTR_SET( sctp_dst, *value )
}
}
static void
assign_udp_port( const oxm_match_header *hdr, match *match ) {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
if ( *hdr == OXM_OF_UDP_SRC ) {
MATCH_ATTR_SET( udp_src, *value )
}
if ( *hdr == OXM_OF_UDP_DST ) {
MATCH_ATTR_SET( udp_dst, *value )
}
}
static void
assign_tcp_port( const oxm_match_header *hdr, match *match ) {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof ( oxm_match_header ) );
if ( *hdr == OXM_OF_TCP_SRC ) {
MATCH_ATTR_SET( tcp_src, *value );
}
if ( *hdr == OXM_OF_TCP_DST ) {
MATCH_ATTR_SET( tcp_dst, *value );
}
}
static void
assign_ipv4_addr( const oxm_match_header *hdr, match *match ) {
const uint32_t *addr = ( const uint32_t * ) ( ( const uint8_t * ) hdr + sizeof ( oxm_match_header ) );
const uint32_t *mask;
switch ( *hdr ) {
case OXM_OF_IPV4_SRC: {
MATCH_ATTR_SET( ipv4_src, *addr )
}
break;
case OXM_OF_IPV4_SRC_W: {
mask = ( const uint32_t * ) ( ( const uint8_t * ) addr + sizeof( uint32_t ) );
MATCH_ATTR_MASK_SET( ipv4_src, *addr, *mask )
}
break;
case OXM_OF_IPV4_DST: {
MATCH_ATTR_SET( ipv4_dst, *addr )
}
break;
case OXM_OF_IPV4_DST_W: {
mask = ( const uint32_t * ) ( ( const uint8_t * ) addr + sizeof( uint32_t ) );
MATCH_ATTR_MASK_SET( ipv4_dst, *addr, *mask )
}
break;
default:
assert( 0 );
break;
}
}
static void
assign_vlan_vid( const oxm_match_header *hdr, match *match ) {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof ( oxm_match_header ) );
if ( *hdr == OXM_OF_VLAN_VID ) {
MATCH_ATTR_SET( vlan_vid, *value )
}
else if ( *hdr == OXM_OF_VLAN_VID_W ) {
const uint16_t *mask = ( const uint16_t * ) ( ( const char * ) value + sizeof ( uint16_t ) );
MATCH_ATTR_MASK_SET( vlan_vid, *value, *mask )
}
}
static void
assign_ether_addr( const oxm_match_header *hdr, match *match ) {
const uint8_t *addr = ( const uint8_t * ) hdr + sizeof ( oxm_match_header );
const uint8_t *mask;
switch( *hdr ) {
case OXM_OF_ETH_DST:
MATCH_ARRAY_ATTR_SET( eth_dst, addr, ETH_ADDRLEN )
break;
case OXM_OF_ETH_DST_W:
MATCH_ARRAY_ATTR_SET( eth_dst, addr, ETH_ADDRLEN )
mask = addr + ( sizeof ( uint8_t ) * ETH_ADDRLEN );
MATCH_ARRAY_MASK_SET( eth_dst, mask, ETH_ADDRLEN )
break;
case OXM_OF_ETH_SRC:
MATCH_ARRAY_ATTR_SET( eth_src, addr, ETH_ADDRLEN );
break;
case OXM_OF_ETH_SRC_W:
MATCH_ARRAY_ATTR_SET( eth_src, addr, ETH_ADDRLEN )
mask = addr + ( sizeof ( uint8_t ) * ETH_ADDRLEN );
MATCH_ARRAY_MASK_SET( eth_src, mask, ETH_ADDRLEN )
break;
default:
assert( 0 );
break;
}
}
static void
assign_metadata( const oxm_match_header *hdr, match *match ) {
const uint64_t *value = ( const uint64_t * ) ( ( const char * ) hdr + sizeof ( oxm_match_header ) );
if ( *hdr == OXM_OF_METADATA ) {
MATCH_ATTR_SET( metadata, *value )
}
if ( *hdr == OXM_OF_METADATA_W ) {
value = ( const uint64_t * ) ( ( const char * ) hdr + sizeof ( oxm_match_header ) );
const uint64_t *mask = ( const uint64_t * ) ( ( const char * ) value + sizeof ( uint64_t ) );
MATCH_ATTR_MASK_SET( metadata, *value, *mask )
}
}
static void
assign_pbb_isid( const oxm_match_header *hdr, match *match ) {
const uint8_t *v = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
uint32_t value = ( uint32_t ) ( ( v[ 0 ] << 16 ) + ( v[ 1 ] << 8 ) + v[ 2 ] );
if ( *hdr == OXM_OF_PBB_ISID ) {
MATCH_ATTR_SET( pbb_isid, value );
}
else if ( *hdr == OXM_OF_PBB_ISID_W ) {
MATCH_ATTR_MASK_SET( pbb_isid, value, ( uint32_t ) ( ( v[ 3 ] << 16 ) + ( v[ 4 ] << 8 ) + v[ 5 ] ) );
}
}
static void
_assign_match( match *match, const oxm_match_header *hdr ) {
switch( *hdr ) {
case OXM_OF_IN_PORT: {
const uint32_t *value = ( const uint32_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( in_port, *value )
}
break;
case OXM_OF_IN_PHY_PORT: {
const uint32_t *value = ( const uint32_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( in_phy_port, *value );
}
break;
case OXM_OF_METADATA:
case OXM_OF_METADATA_W: {
assign_metadata( hdr, match );
}
break;
case OXM_OF_ETH_DST:
case OXM_OF_ETH_DST_W:
case OXM_OF_ETH_SRC:
case OXM_OF_ETH_SRC_W: {
assign_ether_addr( hdr, match );
}
break;
case OXM_OF_ETH_TYPE: {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( eth_type, *value )
}
break;
case OXM_OF_VLAN_VID:
case OXM_OF_VLAN_VID_W: {
assign_vlan_vid( hdr, match );
}
break;
case OXM_OF_VLAN_PCP: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( vlan_pcp, *value )
}
break;
case OXM_OF_IP_DSCP: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( ip_dscp, *value )
}
break;
case OXM_OF_IP_ECN: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( ip_ecn, *value )
}
break;
case OXM_OF_IP_PROTO: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( ip_proto, *value )
}
break;
case OXM_OF_IPV4_SRC:
case OXM_OF_IPV4_SRC_W:
case OXM_OF_IPV4_DST:
case OXM_OF_IPV4_DST_W: {
assign_ipv4_addr( hdr, match );
}
break;
case OXM_OF_TCP_SRC:
case OXM_OF_TCP_DST: {
assign_tcp_port( hdr, match );
}
break;
case OXM_OF_UDP_SRC:
case OXM_OF_UDP_DST: {
assign_udp_port( hdr, match );
}
break;
case OXM_OF_SCTP_SRC:
case OXM_OF_SCTP_DST: {
assign_sctp_port( hdr, match );
}
break;
case OXM_OF_ICMPV4_TYPE: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( icmpv4_type, *value )
}
break;
case OXM_OF_ICMPV4_CODE: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( icmpv4_code, *value )
}
break;
case OXM_OF_ARP_OP: {
const uint16_t *value = ( const uint16_t * ) ( ( const char * ) hdr + sizeof ( oxm_match_header ) );
MATCH_ATTR_SET( arp_op, *value )
}
break;
case OXM_OF_ARP_SPA:
case OXM_OF_ARP_SPA_W:
case OXM_OF_ARP_TPA:
case OXM_OF_ARP_TPA_W: {
assign_arp_protocol_addr( hdr, match );
}
break;
case OXM_OF_ARP_SHA:
case OXM_OF_ARP_SHA_W:
case OXM_OF_ARP_THA:
case OXM_OF_ARP_THA_W: {
assign_arp_hardware_addr( hdr, match );
}
break;
case OXM_OF_IPV6_SRC:
case OXM_OF_IPV6_SRC_W:
case OXM_OF_IPV6_DST:
case OXM_OF_IPV6_DST_W: {
assign_ipv6_addr( hdr, match );
}
break;
case OXM_OF_IPV6_FLABEL:
case OXM_OF_IPV6_FLABEL_W: {
assign_ipv6_flabel( hdr, match );
}
break;
case OXM_OF_ICMPV6_TYPE: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( icmpv6_type, *value )
}
break;
case OXM_OF_ICMPV6_CODE: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( icmpv6_code, *value )
}
break;
case OXM_OF_IPV6_ND_TARGET: {
const struct in6_addr *addr = ( const struct in6_addr * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ARRAY_ATTR_SET( ipv6_nd_target, addr->s6_addr, IPV6_ADDRLEN )
}
break;
case OXM_OF_IPV6_ND_SLL:
case OXM_OF_IPV6_ND_TLL: {
assign_ipv6_nd_addr( hdr, match );
}
break;
case OXM_OF_MPLS_LABEL: {
const uint32_t *value = ( const uint32_t * ) ( ( const char * ) hdr + sizeof ( oxm_match_header ) );
MATCH_ATTR_SET( mpls_label, *value )
}
break;
case OXM_OF_MPLS_TC: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( mpls_tc, *value )
}
break;
case OXM_OF_MPLS_BOS: {
const uint8_t *value = ( const uint8_t * ) ( ( const char * ) hdr + sizeof( oxm_match_header ) );
MATCH_ATTR_SET( mpls_bos, *value )
}
break;
case OXM_OF_TUNNEL_ID:
case OXM_OF_TUNNEL_ID_W: {
assign_tunnel_id( hdr, match );
}
break;
case OXM_OF_IPV6_EXTHDR:
case OXM_OF_IPV6_EXTHDR_W: {
assign_ipv6_exthdr( hdr, match );
}
break;
case OXM_OF_PBB_ISID:
case OXM_OF_PBB_ISID_W: {
assign_pbb_isid( hdr, match );
}
break;
default:
error( "Undefined oxm type ( header = %#x, class = %#x, field = %#x, type = %#x, has_mask = %u, length = %u ). ",
*hdr, OXM_TYPE( *hdr ), OXM_CLASS( *hdr ), OXM_FIELD( *hdr ), OXM_HASMASK( *hdr ), OXM_LENGTH( *hdr ) );
break;
}
}
void ( *assign_match )( match *match, const oxm_match_header *hdr ) = _assign_match;
static void
byte_copy_match8( uint8_t *dst, uint8_t *dst_mask, match8 *src, const uint8_t len ) {
for ( uint8_t i = 0; i < len; i++, src++ ) {
dst[ i ] = src->value;
dst_mask[ i ] = src->mask;
}
}
static void
_construct_oxm( oxm_matches *oxm_match, match *match ) {
APPEND_OXM_MATCH( in_port )
APPEND_OXM_MATCH( in_phy_port )
APPEND_OXM_MATCH( eth_type )
APPEND_OXM_MATCH( ip_proto )
if ( match->vlan_vid.valid ) {
append_oxm_match_vlan_vid( oxm_match, match->vlan_vid.value, match->vlan_vid.mask );
}
APPEND_OXM_MATCH( vlan_pcp )
APPEND_OXM_MATCH( icmpv4_type )
APPEND_OXM_MATCH( icmpv6_type )
APPEND_OXM_MATCH( arp_op )
uint8_t eth_addr[ ETH_ADDRLEN ];
uint8_t eth_addr_mask[ ETH_ADDRLEN ];
if ( match->arp_sha[ 0 ].valid ) {
byte_copy_match8( eth_addr, eth_addr_mask, &match->arp_sha[ 0 ], ETH_ADDRLEN );
append_oxm_match_arp_sha( oxm_match, eth_addr, eth_addr_mask );
}
if ( match->arp_spa.valid ) {
append_oxm_match_arp_spa( oxm_match, match->arp_spa.value, match->arp_spa.mask );
}
if ( match->arp_tha[ 0 ].valid ) {
byte_copy_match8( eth_addr, eth_addr_mask, &match->arp_tha[ 0 ], ETH_ADDRLEN );
append_oxm_match_arp_tha( oxm_match, eth_addr, eth_addr_mask );
}
if ( match->arp_tpa.valid ) {
append_oxm_match_arp_tpa( oxm_match, match->arp_tpa.value, match->arp_tpa.mask );
}
if ( match->eth_dst[ 0 ].valid ) {
byte_copy_match8( eth_addr, eth_addr_mask, &match->eth_dst[ 0 ], ETH_ADDRLEN );
append_oxm_match_eth_dst( oxm_match, eth_addr, eth_addr_mask );
}
if ( match->eth_src[ 0 ].valid ) {
byte_copy_match8( eth_addr, eth_addr_mask, &match->eth_src[ 0 ], ETH_ADDRLEN );
append_oxm_match_eth_src( oxm_match, eth_addr, eth_addr_mask );
}
APPEND_OXM_MATCH( icmpv4_code )
APPEND_OXM_MATCH( icmpv6_code )
APPEND_OXM_MATCH( ip_dscp )
APPEND_OXM_MATCH( ip_ecn )
if ( match->ipv4_dst.valid ) {
append_oxm_match_ipv4_dst( oxm_match, match->ipv4_dst.value, match->ipv4_dst.mask );
}
if ( match->ipv4_src.valid ) {
append_oxm_match_ipv4_src( oxm_match, match->ipv4_src.value, match->ipv4_src.mask );
}
struct in6_addr ipv6_addr, ipv6_mask;
if ( match->ipv6_src[ 0 ].valid ) {
byte_copy_match8( ipv6_addr.s6_addr, ipv6_mask.s6_addr, &match->ipv6_src[ 0 ], IPV6_ADDRLEN );
append_oxm_match_ipv6_src( oxm_match, ipv6_addr, ipv6_mask );
}
if ( match->ipv6_dst[ 0 ].valid ) {
byte_copy_match8( ipv6_addr.s6_addr, ipv6_mask.s6_addr, &match->ipv6_dst[ 0 ], IPV6_ADDRLEN );
append_oxm_match_ipv6_dst( oxm_match, ipv6_addr, ipv6_mask );
}
if ( match->ipv6_exthdr.valid ) {
append_oxm_match_ipv6_exthdr( oxm_match, match->ipv6_exthdr.value, match->ipv6_exthdr.mask );
}
if ( match->ipv6_flabel.valid ) {
append_oxm_match_ipv6_flabel( oxm_match, match->ipv6_flabel.value, match->ipv6_flabel.mask );
}
if ( match->ipv6_nd_sll[ 0 ].valid ) {
byte_copy_match8( eth_addr, eth_addr_mask, &match->ipv6_nd_sll[ 0 ], ETH_ADDRLEN );
append_oxm_match_ipv6_nd_sll( oxm_match, eth_addr );
}
if ( match->ipv6_nd_target[ 0 ].valid ) {
byte_copy_match8( ipv6_addr.s6_addr, ipv6_mask.s6_addr, &match->ipv6_nd_target[ 0 ], IPV6_ADDRLEN ) ;
append_oxm_match_ipv6_nd_target( oxm_match, ipv6_addr );
}
if ( match->ipv6_nd_tll[ 0 ].valid ) {
byte_copy_match8( eth_addr, eth_addr_mask, &match->ipv6_nd_tll[ 0 ], ETH_ADDRLEN );
append_oxm_match_ipv6_nd_tll( oxm_match, eth_addr );
}
if ( match->metadata.valid ) {
append_oxm_match_metadata( oxm_match, match->metadata.value, match->metadata.mask );
}
APPEND_OXM_MATCH( mpls_bos )
APPEND_OXM_MATCH( mpls_label )
APPEND_OXM_MATCH( mpls_tc )
APPEND_OXM_MATCH( sctp_dst )
APPEND_OXM_MATCH( sctp_src )
APPEND_OXM_MATCH( tcp_dst )
APPEND_OXM_MATCH( tcp_src )
if ( match->tunnel_id.valid ) {
append_oxm_match_tunnel_id( oxm_match, match->tunnel_id.value, match->tunnel_id.mask );
}
APPEND_OXM_MATCH( udp_dst )
APPEND_OXM_MATCH( udp_src )
if ( match->pbb_isid.valid ) {
append_oxm_match_pbb_isid( oxm_match, match->pbb_isid.value, match->pbb_isid.mask );
}
}
void ( *construct_oxm )( oxm_matches *oxm_match, match *match ) = _construct_oxm;
void
_pack_ofp_match( struct ofp_match *match, const oxm_matches *matches ) {
assert( match != NULL );
uint16_t oxm_len = 0;
uint16_t oxms_len = 0;
uint16_t ofp_match_len = 0;
uint16_t pad_len = 0;
oxm_match_header *oxm_dst, *oxm_src;
if ( matches != NULL && matches->n_matches ) {
uint16_t offset = offsetof( struct ofp_match, oxm_fields );
oxm_dst = ( oxm_match_header * ) ( ( char * ) match + offset );
list_element *elem = matches->list;
while ( elem != NULL ) {
oxm_src = ( oxm_match_header * ) elem->data;
oxm_len = ( uint16_t ) ( sizeof( oxm_match_header ) + OXM_LENGTH( *oxm_src ) );
memcpy( oxm_dst, oxm_src, oxm_len );
oxms_len = ( uint16_t ) ( oxms_len + oxm_len );
oxm_dst = ( oxm_match_header * ) ( ( char * ) oxm_dst + oxm_len );
elem = elem->next;
}
}
ofp_match_len = ( uint16_t ) ( offsetof( struct ofp_match, oxm_fields ) + oxms_len );
match->type = OFPMT_OXM;
match->length = ( uint16_t ) ( ofp_match_len ); // exclude padding length
pad_len = ( uint16_t ) PADLEN_TO_64( ofp_match_len );
if ( pad_len > 0 ) {
memset( ( char * ) match + ofp_match_len, 0, pad_len );
}
}
void ( *pack_ofp_match )( struct ofp_match *match, const oxm_matches *matches ) = _pack_ofp_match;
static uint32_t *
assign_oxm_id( uint32_t *oxm_id, const uint64_t capability, enum oxm_ofb_match_fields oxm_type, uint16_t *len ) {
assert( oxm_id != NULL );
assert( len != NULL );
if ( capability != 0 ) {
*oxm_id = oxm_attr_field( true, oxm_type );
*len = ( uint16_t ) ( *len + sizeof( uint32_t ) );
oxm_id++;
}
return oxm_id;
}
static uint16_t
_assign_oxm_ids( uint32_t *oxm_id, match_capabilities *match_cap ) {
const match_capabilities c = *match_cap;
uint16_t total_len = 0;
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IN_PORT, OFPXMT_OFB_IN_PORT, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IN_PHY_PORT, OFPXMT_OFB_IN_PHY_PORT, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_METADATA, OFPXMT_OFB_METADATA, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ETH_DST, OFPXMT_OFB_ETH_DST, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ETH_SRC, OFPXMT_OFB_ETH_SRC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ETH_TYPE, OFPXMT_OFB_ETH_TYPE, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_VLAN_VID, OFPXMT_OFB_VLAN_VID, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_VLAN_PCP, OFPXMT_OFB_VLAN_PCP, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IP_DSCP, OFPXMT_OFB_IP_DSCP, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IP_ECN, OFPXMT_OFB_IP_ECN, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IP_PROTO, OFPXMT_OFB_IP_PROTO, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV4_SRC, OFPXMT_OFB_IPV4_SRC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV4_DST, OFPXMT_OFB_IPV4_DST, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_TCP_SRC, OFPXMT_OFB_TCP_SRC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_TCP_DST, OFPXMT_OFB_TCP_DST, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_UDP_SRC, OFPXMT_OFB_UDP_SRC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_UDP_DST, OFPXMT_OFB_UDP_DST, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_SCTP_SRC, OFPXMT_OFB_SCTP_SRC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_SCTP_DST, OFPXMT_OFB_SCTP_DST, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ICMPV4_TYPE, OFPXMT_OFB_ICMPV4_TYPE, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ICMPV4_CODE, OFPXMT_OFB_ICMPV4_CODE, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ARP_OP, OFPXMT_OFB_ARP_OP, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ARP_SPA, OFPXMT_OFB_ARP_SPA, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ARP_TPA, OFPXMT_OFB_ARP_TPA, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ARP_SHA, OFPXMT_OFB_ARP_SHA, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ARP_THA, OFPXMT_OFB_ARP_THA, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_SRC, OFPXMT_OFB_IPV6_SRC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_DST, OFPXMT_OFB_IPV6_DST, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_FLABEL, OFPXMT_OFB_IPV6_FLABEL, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ICMPV6_TYPE, OFPXMT_OFB_ICMPV6_TYPE, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_ICMPV6_CODE, OFPXMT_OFB_ICMPV6_CODE, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_ND_TARGET, OFPXMT_OFB_IPV6_ND_TARGET, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_ND_SLL, OFPXMT_OFB_IPV6_ND_SLL, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_ND_TLL, OFPXMT_OFB_IPV6_ND_TLL, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_MPLS_LABEL, OFPXMT_OFB_MPLS_LABEL, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_MPLS_TC, OFPXMT_OFB_MPLS_TC, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_MPLS_BOS, OFPXMT_OFB_MPLS_BOS, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_PBB_ISID, OFPXMT_OFB_PBB_ISID, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_TUNNEL_ID, OFPXMT_OFB_TUNNEL_ID, &total_len );
oxm_id = assign_oxm_id( oxm_id, c & MATCH_IPV6_EXTHDR, OFPXMT_OFB_IPV6_EXTHDR, &total_len );
return total_len;
}
uint16_t ( *assign_oxm_ids )( uint32_t *oxm_id, match_capabilities *match_cap ) = _assign_oxm_ids;
/*
* Local variables:
* c-basic-offset: 2
* indent-tabs-mode: nil
* End:
*/