void construct_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 *dst, *src; if ( matches != NULL ) { uint16_t offset = offsetof( struct ofp_match, oxm_fields ); dst = ( oxm_match_header * ) ( ( char * ) match + offset ); list_element *elem = matches->list; while ( elem != NULL ) { src = ( oxm_match_header * ) elem->data; hton_oxm_match( dst, src ); oxm_len = ( uint16_t ) ( sizeof( oxm_match_header ) + OXM_LENGTH( *src ) ); oxms_len = ( uint16_t ) ( oxms_len + oxm_len ); dst = ( oxm_match_header * ) ( ( char * ) dst + oxm_len ); elem = elem->next; } }
VALUE ofp_match_to_r_match( const struct ofp_match *match ) { assert( match != NULL ); assert( match->length >= offsetof( struct ofp_match, oxm_fields ) ); uint16_t oxms_len = 0; uint16_t oxm_len = 0; const oxm_match_header *src; uint16_t offset = offsetof( struct ofp_match, oxm_fields ); oxms_len = ( uint16_t ) ( match->length - offset ); src = ( const oxm_match_header * ) ( ( const char * ) match + offset ); VALUE r_attributes = rb_hash_new(); while ( oxms_len > sizeof( oxm_match_header ) ) { oxm_len = OXM_LENGTH( *src ); unpack_r_match( src, r_attributes ); offset = ( uint16_t ) ( sizeof( oxm_match_header ) + oxm_len ); if ( oxms_len < offset ) { break; } oxms_len = ( uint16_t ) ( oxms_len - offset ); src = ( const oxm_match_header * ) ( ( const char * ) src + offset ); } return rb_funcall( rb_eval_string( "Trema::Match" ), rb_intern( "new" ), 1, r_attributes ); }
oxm_matches * parse_ofp_match( struct ofp_match *match ) { assert( match != NULL ); assert( ntohs( match->length ) >= offsetof( struct ofp_match, oxm_fields ) ); uint16_t oxms_len = 0; uint16_t oxm_len = 0; oxm_match_header *dst, *src; oxm_matches *matches = create_oxm_matches(); uint16_t offset = offsetof( struct ofp_match, oxm_fields ); oxms_len = ( uint16_t ) ( ntohs( match->length ) - offset ); src = ( oxm_match_header * ) ( ( char * ) match + offset ); while ( oxms_len > sizeof( oxm_match_header ) ) { oxm_len = OXM_LENGTH( ntohl( *src ) ); dst = ( oxm_match_header * ) xcalloc( 1, sizeof( oxm_match_header ) + oxm_len ); ntoh_oxm_match( dst, src ); append_oxm_match( matches, dst ); offset = ( uint16_t ) ( sizeof( oxm_match_header ) + oxm_len ); if ( oxms_len < offset ) { break; } oxms_len = ( uint16_t ) ( oxms_len - offset ); src = ( oxm_match_header * ) ( ( char * ) src + offset ); } return matches; }
static flow_stats * retrieve_flow_stats( uint32_t *nr_stats, const uint8_t table_id, const uint32_t out_port, const uint32_t out_group, const uint64_t cookie, const uint64_t cookie_mask, const struct ofp_match *ofp_match ) { match *flow_match = create_match(); size_t match_len = 0; if ( ofp_match != NULL ) { match_len = ofp_match->length - offsetof( struct ofp_match, oxm_fields ); // translate the ofp_match to datapath match. const oxm_match_header *hdr = ( const oxm_match_header * ) ofp_match->oxm_fields; while ( match_len > 0 ) { assign_match( flow_match, hdr ); match_len -= ( sizeof( *hdr ) + OXM_LENGTH( *hdr ) ); if ( match_len > 0 ) { hdr = ( const oxm_match_header * ) ( ( const char * ) hdr + sizeof( *hdr ) + OXM_LENGTH( *hdr ) ); } } }
static void 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 bool append_oxm_match_eth_addr( oxm_matches *matches, oxm_match_header header, uint8_t addr[ OFP_ETH_ALEN ] ) { assert( matches != NULL ); assert( OXM_LENGTH( header ) == ( OFP_ETH_ALEN * sizeof( uint8_t ) ) ); oxm_match_header *buf = xmalloc( sizeof( oxm_match_header ) + ( OFP_ETH_ALEN * sizeof( uint8_t ) ) ); *buf = header; uint8_t *value = ( uint8_t * ) ( ( char * ) buf + sizeof( oxm_match_header ) ); memcpy( value, addr, OFP_ETH_ALEN * sizeof( uint8_t ) ); return append_oxm_match( matches, buf ); }
static bool append_oxm_match_64( oxm_matches *matches, oxm_match_header header, uint64_t value ) { assert( matches != NULL ); assert( OXM_LENGTH( header ) == sizeof( uint64_t ) ); oxm_match_header *buf = xmalloc( sizeof( oxm_match_header ) + sizeof( uint64_t ) ); *buf = header; uint64_t *v = ( uint64_t * ) ( ( char * ) buf + sizeof( oxm_match_header ) ); *v = value; return append_oxm_match( matches, buf ); }
void ofl_structs_match_convert_pktf2oflm(struct hmap * hmap_packet_fields, struct hmap * hmap_ofl_match) /* * Used to convert between a hmap of "struct packet_fields" to "struct ofl_match" */ { struct packet_fields *iter; HMAP_FOR_EACH(iter,struct packet_fields, hmap_node, hmap_packet_fields) { struct ofl_match_tlv * new_entry = (struct ofl_match_tlv *) malloc(sizeof(struct ofl_match_tlv)); new_entry->header = iter->header; new_entry->value = (uint8_t *) malloc(OXM_LENGTH(new_entry->header)); memcpy(new_entry->value, iter->value,OXM_LENGTH(new_entry->header)); hmap_insert_fast(hmap_ofl_match, &new_entry->hmap_node, hash_int(new_entry->header, 0)); } }
static bool append_oxm_match_32w( oxm_matches *matches, oxm_match_header header, uint32_t value, uint32_t mask ) { assert( matches != NULL ); assert( OXM_LENGTH( header ) == ( sizeof( uint32_t ) * 2 ) ); oxm_match_header *buf = xmalloc( sizeof( oxm_match_header ) + sizeof( uint32_t ) * 2 ); *buf = header; uint32_t *v = ( uint32_t * ) ( ( char * ) buf + sizeof( oxm_match_header ) ); *v = value; v = ( uint32_t * ) ( ( char * ) v + sizeof( uint32_t ) ); *v = mask; return append_oxm_match( matches, buf ); }
static bool append_oxm_match_ipv6_addr( oxm_matches *matches, oxm_match_header header, struct in6_addr addr, struct in6_addr mask ) { assert( matches != NULL ); uint8_t length = OXM_LENGTH( header ); oxm_match_header *buf = xmalloc( sizeof( oxm_match_header ) + length ); *buf = header; void *p = ( char * ) buf + sizeof( oxm_match_header ); memcpy( p, &addr, sizeof( struct in6_addr ) ); if ( OXM_HASMASK( header ) ) { p = ( char * ) p + sizeof( struct in6_addr ); memcpy( p, &mask, sizeof( struct in6_addr ) ); } return append_oxm_match( matches, buf ); }
size_t ofl_actions_ofp_len(struct ofl_action_header *action, struct ofl_exp *exp) { switch (action->type) { case OFPAT_OUTPUT: return sizeof(struct ofp_action_output); case OFPAT_COPY_TTL_OUT: case OFPAT_COPY_TTL_IN: return sizeof(struct ofp_action_header); case OFPAT_SET_MPLS_TTL: return sizeof(struct ofp_action_mpls_ttl); case OFPAT_DEC_MPLS_TTL: return sizeof(struct ofp_action_header); case OFPAT_PUSH_VLAN: case OFPAT_PUSH_PBB: case OFPAT_PUSH_MPLS: return sizeof(struct ofp_action_push); case OFPAT_POP_VLAN: case OFPAT_POP_PBB: return sizeof(struct ofp_action_header); case OFPAT_POP_MPLS: return sizeof(struct ofp_action_pop_mpls); case OFPAT_SET_QUEUE: return sizeof(struct ofp_action_set_queue); case OFPAT_GROUP: return sizeof(struct ofp_action_group); case OFPAT_SET_NW_TTL: return sizeof(struct ofp_action_nw_ttl); case OFPAT_DEC_NW_TTL: return sizeof(struct ofp_action_header); case OFPAT_SET_FIELD: { struct ofl_action_set_field *a = (struct ofl_action_set_field *) action; return sizeof(struct ofp_action_set_field) + ROUND_UP(OXM_LENGTH(a->field->header),8) ; } case OFPAT_EXPERIMENTER: { if (exp == NULL || exp->act == NULL || exp->act->ofp_len == NULL) { OFL_LOG_WARN(LOG_MODULE, "requesting experimenter length, but no callback was given."); return -1; } return exp->act->ofp_len(action); } default: return 0; } }
uint16_t get_oxm_matches_length( const oxm_matches *matches ) { debug( "Calculating the total length of matches." ); int length = 0; if ( matches != NULL ) { list_element *match = matches->list; while ( match != NULL ) { oxm_match_header *header = match->data; length += ( int ) ( ( uint8_t ) OXM_LENGTH( *header ) + sizeof( oxm_match_header ) ); match = match->next; } } debug( "Total length of matches = %d.", length ); assert( length <= UINT16_MAX ); return ( uint16_t ) length; }
/* Two matches strictly match if their wildcard fields are the same, and all the * non-wildcarded fields match on the same exact values. * NOTE: Handling of bitmasked fields is not specified. In this implementation * masked fields are checked for equality, and only unmasked bits are compared * in the field. */ bool match_std_strict(struct ofl_match *a, struct ofl_match *b) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; bool has_mask; /* Both matches all wildcarded */ if(!a->header.length && !b->header.length ) return true; /* If the matches differ in length, there is no reason to compare */ if (a->header.length != b->header.length) return false; /* Loop through the flow_mod match fields */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields) { /* Check presence of match field in flow entry */ flow_entry_match = oxm_match_lookup(flow_mod_match->header, b); if (!flow_entry_match) { return false; } /* At this point match length and has_mask are equal */ has_mask = OXM_HASMASK(flow_mod_match->header); field_len = OXM_LENGTH(flow_mod_match->header); flow_mod_val = flow_mod_match->value; flow_entry_val = flow_entry_match->value; if (has_mask) { field_len /= 2; flow_mod_mask = flow_mod_match->value + field_len; flow_entry_mask = flow_entry_match->value + field_len; } switch (field_len) { case 1: if (has_mask) { if (!strict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_8(flow_mod_val, flow_entry_val)) return false; } break; case 2: if (has_mask) { if (!strict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_16(flow_mod_val, flow_entry_val)) return false; } break; case 4: if (has_mask) { if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_32(flow_mod_val, flow_entry_val)) return false; } break; case 6: if (has_mask) { if (!strict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_48(flow_mod_val, flow_entry_val)) return false; } break; case 8: if (has_mask) { if (!strict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_64(flow_mod_val, flow_entry_val)) return false; } break; case 16: if (has_mask) { if (!strict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_128(flow_mod_val, flow_entry_val)) return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* HMAP_FOR_EACH */ /* If we get here, all match fields in flow_mod were equal to the ones in flow entry */ /* There can't be more fields in the flow entry as the lengths are the same */ return true; }
/* Two flow matches overlap if there exists a packet which both match structures match on. * Conversely, two flow matches do not overlap if they share at least one match field with * incompatible value/mask fields that can't match any packet. */ bool match_std_overlap(struct ofl_match *a, struct ofl_match *b, struct ofl_exp *exp) { uint64_t all_mask[2] = {~0L, ~0L}; struct ofl_match_tlv *f_a; struct ofl_match_tlv *f_b; int header, header_m; int field_len; uint8_t *val_a, *mask_a; uint8_t *val_b, *mask_b; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(f_a, struct ofl_match_tlv, hmap_node, &a->match_fields) { val_a = f_a->value; switch (OXM_VENDOR(f_a->header)) { case (OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(f_a->header); if (OXM_HASMASK(f_a->header)) { field_len /= 2; header = (f_a->header & 0xfffffe00) | field_len; header_m = f_a->header; mask_a = f_a->value + field_len; } else { header = f_a->header; header_m = (f_a->header & 0xfffffe00) | 0x100 | (field_len << 1); /* Set a dummy mask with all bits set to 0 (valid) */ mask_a = (uint8_t *) all_mask; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->overlap_a == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->overlap_a(f_a, &field_len, &val_a, &mask_a, &header, &header_m, all_mask); break; default: break; } /*switch class*/ /* Check presence of corresponding match field in flow entry b * Need to check for both masked and non-masked field */ f_b = oxm_match_lookup(header, b); if (!f_b) f_b = oxm_match_lookup(header_m, b); if (f_b) { switch (OXM_VENDOR(f_b->header)) { case (OFPXMC_OPENFLOW_BASIC): val_b = f_b->value; if (OXM_HASMASK(f_b->header)) { mask_b = f_b->value + field_len; } else { /* Set a dummy mask with all bits set to 0 (valid) */ mask_b = (uint8_t *) all_mask; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->overlap_b == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->overlap_b(f_b, &field_len, &val_b, &mask_b, all_mask); break; default: break; } /*switch class*/ switch (field_len) { case 1: if (incompatible_8(val_a, val_b, mask_a, mask_b)) { return false; } break; case 2: if (incompatible_16(val_a, val_b, mask_a, mask_b)) { return false; } break; case 4: if (incompatible_32(val_a, val_b, mask_a, mask_b)) { return false; } break; case 6: if (incompatible_48(val_a, val_b, mask_a, mask_b)) { return false; } break; case 8: if (incompatible_64(val_a, val_b, mask_a, mask_b)) { return false; } break; case 16: if (incompatible_128(val_a, val_b, mask_a, mask_b)) { return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* if (f_b) */ } /* HMAP_FOR_EACH */ /* If we get here, none of the common match fields in a and b were found incompatible. * The flow entries overlap */ return true; }
/* Flow entry (a) matches flow entry (b) non-strictly if (a) matches whenever (b) matches. * Thus, flow (a) must not have more match fields than (b) and all match fields in (a) must * be equal or narrower in (b). * NOTE: Handling of bitmasked fields is not specified. In this implementation * a masked field of (a) matches the field of (b) if all masked bits of (b) are * also masked in (a), and for each unmasked bits of (b) , the bit is either * masked in (a), or is set to the same value in both matches. * */ bool match_std_nonstrict(struct ofl_match *a, struct ofl_match *b, struct ofl_exp *exp) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; bool has_mask; /* Flow a is fully wildcarded */ if (!a->header.length) return true; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields) { /* Check presence of match field in flow entry */ flow_entry_match = oxm_match_lookup(flow_mod_match->header, b); if (!flow_entry_match) { return false; } /* At this point match length and has_mask are equal */ has_mask = OXM_HASMASK(flow_mod_match->header); flow_mod_val = flow_mod_match->value; flow_entry_val = flow_entry_match->value; switch (OXM_VENDOR(flow_mod_match->header)) { case (OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(flow_mod_match->header); if (has_mask) { field_len /= 2; flow_mod_mask = flow_mod_match->value + field_len; flow_entry_mask = flow_entry_match->value + field_len; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->match_std == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->match_std(flow_mod_match, flow_entry_match, &field_len, &flow_mod_val, &flow_entry_val, &flow_mod_mask, &flow_entry_mask); break; default: break; } switch (field_len) { case 1: if (has_mask) { if (!nonstrict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_8(flow_mod_val, flow_entry_val)) return false; } break; case 2: if (has_mask) { if (!nonstrict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_16(flow_mod_val, flow_entry_val)) return false; } break; case 3: if (has_mask) { if (!nonstrict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_24(flow_mod_val, flow_entry_val)) return false; } break; case 4: if (has_mask) { if (!nonstrict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_32(flow_mod_val, flow_entry_val)) return false; } break; case 6: if (has_mask) { if (!nonstrict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_48(flow_mod_val, flow_entry_val)) return false; } break; case 8: if (has_mask) { if (!nonstrict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_64(flow_mod_val, flow_entry_val)) return false; } break; case 16: if (has_mask) { if (!nonstrict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_128(flow_mod_val, flow_entry_val)) return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* HMAP_FOR_EACH */ /* If we get here, all match fields in flow a were equal or wider than the ones in b */ /* It doesn't matter if there are further fields in b */ return true; }
/* Two matches strictly match if their wildcard fields are the same, and all the * non-wildcarded fields match on the same exact values. * NOTE: Handling of bitmasked fields is not specified. In this implementation * masked fields are checked for equality, and only unmasked bits are compared * in the field. */ bool match_std_strict(struct ofl_match *a, struct ofl_match *b, struct ofl_exp *exp) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; uint8_t oxm_field; bool has_mask; /* Both matches all wildcarded */ if(!a->header.length && !b->header.length ) return true; /* If the matches differ in length, there is no reason to compare */ if (a->header.length != b->header.length) return false; /* Loop through the flow_mod match fields */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields) { /* Check presence of match field in flow entry */ flow_entry_match = oxm_match_lookup(flow_mod_match->header, b); if (!flow_entry_match) { return false; } /* At this point match length and has_mask are equal */ oxm_field = OXM_FIELD(flow_mod_match->header); has_mask = OXM_HASMASK(flow_mod_match->header); flow_mod_val = flow_mod_match->value; flow_entry_val = flow_entry_match->value; switch (OXM_VENDOR(flow_mod_match->header)) { case (OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(flow_mod_match->header); if (has_mask) { field_len /= 2; flow_mod_mask = flow_mod_val + field_len; flow_entry_mask = flow_entry_val + field_len; } break; case (OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->match_std == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->match_std(flow_mod_match, flow_entry_match, &field_len, &flow_mod_val, &flow_entry_val, &flow_mod_mask, &flow_entry_mask); break; default: break; } switch (field_len) { case 1: if (has_mask) { if (!strict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } else { if (!match_8(flow_mod_val, flow_entry_val)){ return false; } } break; case 2: if (has_mask) { if (!strict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } else { if (!match_16(flow_mod_val, flow_entry_val)){ return false; } } break; case 3: if (has_mask) { if (!strict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_24(flow_mod_val, flow_entry_val)){ return false; } } break; case 4: if (has_mask) { /* Quick and dirty fix for IP addresses matching TODO: Matching needs a huge refactoring */ if (oxm_field == OFPXMT_OFB_IPV4_SRC || oxm_field == OFPXMT_OFB_IPV4_DST || oxm_field == OFPXMT_OFB_ARP_SPA || oxm_field == OFPXMT_OFB_ARP_TPA) { if (!strict_mask_ip(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } else { if (!match_32(flow_mod_val, flow_entry_val)){ return false; } } break; case 6: if (has_mask) { if (!strict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } else { if (!match_48(flow_mod_val, flow_entry_val)){ return false; } } break; case 8: if (has_mask) { if (!strict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } else { if (!match_64(flow_mod_val, flow_entry_val)){ return false; } } break; case 16: if (has_mask) { if (!strict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; } } else { if (!match_128(flow_mod_val, flow_entry_val)){ return false; } } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* HMAP_FOR_EACH */ /* If we get here, all match fields in flow_mod were equal to the ones in flow entry */ /* There can't be more fields in the flow entry as the lengths are the same */ return true; }
/* Returns true if the fields in *packet matches the flow entry in *flow_match */ bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet, struct ofl_exp *exp){ struct ofl_match_tlv *f; struct ofl_match_tlv *packet_f; bool has_mask; int field_len; int packet_header; uint8_t *flow_val, *flow_mask= NULL; uint8_t *packet_val; if (flow_match->header.length == 0) return true; /* Loop over the flow entry's match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields) { /* Check presence of match field in packet */ has_mask = OXM_HASMASK(f->header); packet_header = f->header; switch (OXM_VENDOR(f->header)) { case(OFPXMC_OPENFLOW_BASIC): field_len = OXM_LENGTH(f->header); flow_val = f->value; if (has_mask) { /* Clear the has_mask bit and divide the field_len by two in the packet field header */ field_len /= 2; packet_header &= 0xfffffe00; packet_header |= field_len; flow_mask = f->value + field_len; } break; case(OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->match == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->match(f, &packet_header, &field_len, &flow_val, &flow_mask); break; default: break; } /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { if (f->header==OXM_OF_VLAN_VID && *((uint16_t *) f->value)==OFPVID_NONE) { /* There is no VLAN tag, as required */ continue; } return false; } /* Compare the flow and packet field values, considering the mask, if any */ switch (OXM_VENDOR(f->header)) { case(OFPXMC_OPENFLOW_BASIC): packet_val = packet_f->value; break; case(OFPXMC_EXPERIMENTER): if (exp == NULL || exp->field == NULL || exp->field->compare == NULL) { VLOG_WARN(LOG_MODULE,"Received match is experimental, but no callback was given."); ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_TYPE); } exp->field->compare(f, packet_f, &packet_val); break; default: break; } switch (field_len) { case 1: if (has_mask) { if (!match_mask8(flow_val, flow_mask, packet_val)) return false; } else { if (!match_8(flow_val, packet_val)) return false; } break; case 2: switch (packet_header) { case OXM_OF_VLAN_VID: { /* Special handling for VLAN ID */ uint16_t flow_vlan_id = *((uint16_t*) flow_val); if (flow_vlan_id == OFPVID_NONE) { /* Packet has a VLAN tag when none should be there */ return false; } else if (flow_vlan_id == OFPVID_PRESENT) { /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ flow_vlan_id &= VLAN_VID_MASK; if (has_mask){ if (!match_mask16((uint8_t*) &flow_vlan_id, flow_mask, packet_val)){ return false; } } else { if (!match_16((uint8_t*) &flow_vlan_id, packet_val)){ return false; } } } break; } case OXM_OF_IPV6_EXTHDR: { /* Special handling for IPv6 Extension header */ uint16_t flow_eh = *((uint16_t *) flow_val); uint16_t packet_eh = *((uint16_t *) packet_val); if ((flow_eh & packet_eh) != flow_eh) { /* The packet doesn't have all extension headers specified in the flow */ return false; } break; } default: if (has_mask) { if (!match_mask16(flow_val, flow_mask, packet_val)) return false; } else { if (!match_16(flow_val, packet_val)) return false; } break; } break; case 3: if (has_mask) { if (!match_mask24(flow_val, flow_mask, packet_val)) return false; } else { if (!match_24(flow_val, packet_val)) return false; } break; case 4: if (has_mask) { if (!match_mask32(flow_val, flow_mask, packet_val)) return false; } else { if (!match_32(flow_val, packet_val)) return false; } break; case 6: if (has_mask) { if (!match_mask48(flow_val, flow_mask, packet_val)) return false; } else { if (!match_48(flow_val, packet_val)) return false; } break; case 8: if (has_mask) { if (!match_mask64(flow_val, flow_mask, packet_val)) return false; } else { if (!match_64(flow_val, packet_val)) return false; } break; case 16: if (has_mask) { if (!match_mask128(flow_val, flow_mask, packet_val)) return false; } else { if (!match_128(flow_val, packet_val)) return false; } break; default: /* Should never happen */ break; } } /* If we get here, all match fields in the flow entry matched the packet */ return true; }
ofl_err ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action_header **dst, struct ofl_exp *exp) { if (*len < sizeof(struct ofp_action_header)) { OFL_LOG_WARN(LOG_MODULE, "Received action is too short (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received action has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } if ((ntohs(src->len) % 8) != 0) { OFL_LOG_WARN(LOG_MODULE, "Received action length is not a multiple of 64 bits (%u).", ntohs(src->len)); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } switch (ntohs(src->type)) { case OFPAT_OUTPUT: { struct ofp_action_output *sa; struct ofl_action_output *da; if (*len < sizeof(struct ofp_action_output)) { OFL_LOG_WARN(LOG_MODULE, "Received OUTPUT action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_output *)src; if (ntohl(sa->port) == 0 || (ntohl(sa->port) > OFPP_MAX && ntohl(sa->port) < OFPP_IN_PORT) || ntohl(sa->port) == OFPP_ANY) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(sa->port)); OFL_LOG_WARN(LOG_MODULE, "Received OUTPUT action has invalid port (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); } da = (struct ofl_action_output *)malloc(sizeof(struct ofl_action_output)); da->port = ntohl(sa->port); da->max_len = ntohs(sa->max_len); *len -= sizeof(struct ofp_action_output); *dst = (struct ofl_action_header *)da; break; } case OFPAT_COPY_TTL_OUT: { //ofp_action_header length was already checked *len -= sizeof(struct ofp_action_header); *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header)); break; } case OFPAT_COPY_TTL_IN: { //ofp_action_header length was already checked *len -= sizeof(struct ofp_action_header); *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header)); break; } case OFPAT_SET_MPLS_TTL: { struct ofp_action_mpls_ttl *sa; struct ofl_action_mpls_ttl *da; if (*len < sizeof(struct ofp_action_mpls_ttl)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TTL action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_mpls_ttl *)src; da = (struct ofl_action_mpls_ttl *)malloc(sizeof(struct ofl_action_mpls_ttl)); da->mpls_ttl = sa->mpls_ttl; *len -= sizeof(struct ofp_action_mpls_ttl); *dst = (struct ofl_action_header *)da; break; } case OFPAT_DEC_MPLS_TTL: { //ofp_action_header length was already checked *len -= sizeof(struct ofp_action_mpls_ttl); *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header)); break; } case OFPAT_PUSH_VLAN: case OFPAT_PUSH_PBB: case OFPAT_PUSH_MPLS: { struct ofp_action_push *sa; struct ofl_action_push *da; if (*len < sizeof(struct ofp_action_push)) { OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS/PBB action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_push *)src; if (((ntohs(src->type) == OFPAT_PUSH_VLAN) && (ntohs(sa->ethertype) != ETH_TYPE_VLAN && ntohs(sa->ethertype) != ETH_TYPE_VLAN_PBB)) || ((ntohs(src->type) == OFPAT_PUSH_MPLS) && (ntohs(sa->ethertype) != ETH_TYPE_MPLS && ntohs(sa->ethertype) != ETH_TYPE_MPLS_MCAST)) || ((ntohs(src->type) == OFPAT_PUSH_PBB) && (ntohs(sa->ethertype) != ETH_TYPE_PBB))) { OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS/PBB has invalid eth type. (%u)", ntohs(sa->ethertype)); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_push *)malloc(sizeof(struct ofl_action_push)); da->ethertype = ntohs(sa->ethertype); *len -= sizeof(struct ofp_action_push); *dst = (struct ofl_action_header *)da; break; } case OFPAT_POP_VLAN: case OFPAT_POP_PBB: { //ofp_action_header length was already checked *len -= sizeof(struct ofp_action_header); *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header)); break; } case OFPAT_POP_MPLS: { struct ofp_action_pop_mpls *sa; struct ofl_action_pop_mpls *da; if (*len < sizeof(struct ofp_action_pop_mpls)) { OFL_LOG_WARN(LOG_MODULE, "Received POP_MPLS action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_pop_mpls *)src; da = (struct ofl_action_pop_mpls *)malloc(sizeof(struct ofl_action_pop_mpls)); da->ethertype = ntohs(sa->ethertype); *len -= sizeof(struct ofp_action_pop_mpls); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_QUEUE: { struct ofp_action_set_queue *sa; struct ofl_action_set_queue *da; if (*len < sizeof(struct ofp_action_set_queue)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_QUEUE action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_set_queue *)src; da = (struct ofl_action_set_queue *)malloc(sizeof(struct ofl_action_set_queue)); da->queue_id = ntohl(sa->queue_id); *len -= sizeof(struct ofp_action_set_queue); *dst = (struct ofl_action_header *)da; break; } case OFPAT_GROUP: { struct ofp_action_group *sa; struct ofl_action_group *da; if (*len < sizeof(struct ofp_action_group)) { OFL_LOG_WARN(LOG_MODULE, "Received GROUP action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_group *)src; if (ntohl(sa->group_id) > OFPG_MAX) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *gs = ofl_group_to_string(ntohl(sa->group_id)); OFL_LOG_WARN(LOG_MODULE, "Received GROUP action has invalid group id (%s).", gs); free(gs); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_GROUP); } da = (struct ofl_action_group *)malloc(sizeof(struct ofl_action_group)); da->group_id = ntohl(sa->group_id); *len -= sizeof(struct ofp_action_group); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_NW_TTL: { struct ofp_action_nw_ttl *sa; struct ofl_action_set_nw_ttl *da; if (*len < sizeof(struct ofp_action_nw_ttl)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TTL action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_nw_ttl *)src; da = (struct ofl_action_set_nw_ttl *)malloc(sizeof(struct ofl_action_set_nw_ttl)); da->nw_ttl = sa->nw_ttl; *len -= sizeof(struct ofp_action_nw_ttl); *dst = (struct ofl_action_header *)da; break; } case OFPAT_DEC_NW_TTL: { //ofp_action_header length was already checked *len -= sizeof(struct ofp_action_header); *dst = (struct ofl_action_header *)malloc(sizeof(struct ofl_action_header)); break; } case OFPAT_SET_FIELD: { struct ofp_action_set_field *sa; struct ofl_action_set_field *da; uint8_t *value; sa = (struct ofp_action_set_field*) src; da = (struct ofl_action_set_field *)malloc(sizeof(struct ofl_action_set_field)); da->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); memcpy(&da->field->header,sa->field,4); da->field->header = ntohl(da->field->header); value = (uint8_t *) src + sizeof (struct ofp_action_set_field); da->field->value = malloc(OXM_LENGTH(da->field->header)); /*TODO: need to check if other fields are valid */ if(da->field->header == OXM_OF_IN_PORT || da->field->header == OXM_OF_IN_PHY_PORT || da->field->header == OXM_OF_METADATA || da->field->header == OXM_OF_IPV6_EXTHDR){ return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_SET_TYPE); } switch(OXM_LENGTH(da->field->header)){ case 1: case 6: case 16: memcpy(da->field->value , value, OXM_LENGTH(da->field->header)); break; case 2:{ uint16_t v = ntohs(*((uint16_t*) value)); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } case 4:{ uint32_t v; uint8_t field = OXM_FIELD(da->field->header); if( field != 11 && field != 12 && field != 22 && field != 23) v = htonl(*((uint32_t*) value)); else v = *((uint32_t*) value); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } case 8:{ uint64_t v = hton64(*((uint64_t*) value)); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } } *len -= ROUND_UP(ntohs(src->len),8); *dst = (struct ofl_action_header *)da; break; } case OFPAT_EXPERIMENTER: { ofl_err error; if (*len < sizeof(struct ofp_action_experimenter_header)) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } if (exp == NULL || exp->act == NULL || exp->act->unpack == NULL) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER action, but no callback is given."); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER); } error = exp->act->unpack(src, len, dst); if (error) { return error; } break; } default: { OFL_LOG_WARN(LOG_MODULE, "Received unknown action type (%u).", ntohs(src->type)); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); } } (*dst)->type = (enum ofp_action_type)ntohs(src->type); return 0; }
static void set_field(struct packet *pkt, struct ofl_action_set_field *act ) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->valid) { struct packet_fields *iter; /* Search field on the description of the packet. */ HMAP_FOR_EACH_WITH_HASH(iter,struct packet_fields, hmap_node, hash_int(act->field->header,0), &pkt->handle_std->match.match_fields) { /* TODO: Checksum for SCTP and ICMP */ if (iter->header == OXM_OF_IPV4_SRC || iter->header == OXM_OF_IPV4_DST || iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux_old ; aux_old = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux_old, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); if (iter->header == OXM_OF_IP_DSCP) { uint8_t* aux; aux = (uint8_t *)malloc(OXM_LENGTH(iter->header)); memcpy(aux,((uint8_t*)pkt->buffer->data + iter->pos) , OXM_LENGTH(iter->header)); *aux = *aux ^ ((*act->field->value) << 2 ); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , aux , OXM_LENGTH(iter->header)); free(aux); } else if (iter->header == OXM_OF_IP_ECN) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } else { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } // update TCP/UDP checksum struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; if (iter->header == OXM_OF_IPV4_SRC) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_src,htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_dst,htonl(*((uint32_t*) act->field->value))); } } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; if (iter->header == OXM_OF_IPV4_SRC) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } } if (iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux ; aux = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, *aux_old, *aux); free(aux); } else if (iter->header == OXM_OF_IPV4_SRC) { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } pkt->handle_std->valid = false; packet_handle_std_validate(pkt->handle_std); free(aux_old); return; } if (iter->header == OXM_OF_TCP_SRC) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_TCP_DST) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_SRC) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_DST) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, htons(*((uint16_t*) act->field->value))); } if (iter->header == OXM_OF_IPV6_SRC || iter->header == OXM_OF_IPV6_DST || iter->header == OXM_OF_ETH_SRC || iter->header == OXM_OF_ETH_DST || iter->header == OXM_OF_ARP_SPA || iter->header == OXM_OF_ARP_TPA || iter->header == OXM_OF_ARP_SHA || iter->header == OXM_OF_ARP_THA) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } /* Found the field, lets re-write it!! */ uint8_t* tmp = (uint8_t*) malloc(OXM_LENGTH(iter->header)); uint8_t i; for (i=0;i<OXM_LENGTH(iter->header);i++) { memcpy(((uint8_t*)tmp + i) , (act->field->value + OXM_LENGTH(iter->header) - i -1 ), 1); } memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , tmp , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_FIELD action on packet with no corresponding field."); } }
bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ struct ofl_match_tlv *f; struct packet_fields *packet_f; bool ret = false; if (flow_match->header.length == 0){ return true; } /* Loop through the match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields){ /* Check if the field is present in the packet */ // HMAP_FOR_EACH_WITH_HASH(packet_f, struct packet_fields, hmap_node, hash_int(f->header, 0), &packet->match_fields){ HMAP_FOR_EACH(packet_f, struct packet_fields, hmap_node, &packet->match_fields){ if (OXM_TYPE(f->header) == OXM_TYPE(packet_f->header)) { int field_len = OXM_LENGTH(f->header); bool has_mask = OXM_HASMASK(f->header); ret = true; if (has_mask) { field_len = field_len/2; } switch (field_len){ case (sizeof(uint8_t)):{ if (has_mask){ if (pkt_mask8(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_8(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint16_t)):{ if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_VLAN_VID)) { if (*((uint16_t*)f->value) == OFPVID_NONE) return false; // we have vlan tag when we expect none else if (*((uint16_t*)f->value) == OFPVID_PRESENT && has_mask) break; // this is the case where each vlan is a match else *((uint16_t*)f->value) &= VLAN_VID_MASK; // remove CFI bit } if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV6_EXTHDR)){ if (ipv6_eh_match(f->value, packet_f->value) == 0) { return false; } } else if (has_mask){ if (pkt_mask16(f->value,f->value+ field_len, packet_f->value) == 0){ return false; } } else { if (pkt_match_16(f->value, packet_f->value) == 0){ return false; } } break; } case (sizeof(uint32_t)):{ if (has_mask){ if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_DST) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_SRC) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_SPA) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_TPA)){ if (matches_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (pkt_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_DST) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_IPV4_SRC) ||OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_SPA) || OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_ARP_TPA)){ if (matches_32(f->value, packet_f->value) == 0){ return false; } } else { if (pkt_match_32(f->value, packet_f->value) == 0){ return false; } } break; } case (ETH_ADDR_LEN):{ if (has_mask){ if (eth_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (eth_match(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint64_t)):{ if (has_mask) { if (pkt_mask64(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_64(f->value, packet_f->value) == 0){ return false; } break; } case (16):{ if (has_mask){ if (ipv6_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (ipv6_match(f->value, packet_f->value) == 0){ return false; } break; } } // end of switch case } // end of if (OXM_TYPE(f->header) == OXM_TYPE(packet_f->header)) } // end of packet_match loop if (OXM_TYPE(f->header) == OXM_TYPE(OXM_OF_VLAN_VID)) if (*((uint16_t*)f->value) == OFPVID_NONE) ret = true; // in case the packet has no vlan and this is what was expected if (!ret) return ret; else ret = false; } // end of flow_match loop return true; }
bool match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; bool ret = false; /*Matches all flows */ if(!a->header.length ) return true; /* Loop through the match fields */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields){ /* Check if the field is present in the flow entry */ HMAP_FOR_EACH_WITH_HASH(flow_entry_match, struct ofl_match_tlv, hmap_node, hash_int(flow_mod_match->header, 0), &b->match_fields){ int field_len = OXM_LENGTH(flow_mod_match->header); bool has_mask; /* Check if both fields have or not a mask */ if ( (OXM_HASMASK(flow_mod_match->header) && !OXM_HASMASK(flow_entry_match->header)) || (!OXM_HASMASK(flow_mod_match->header) && OXM_HASMASK(flow_entry_match->header))){ return false; } ret = true; has_mask = OXM_HASMASK(flow_mod_match->header); switch (field_len){ case (sizeof(uint8_t)):{ if (has_mask){ if (nonstrict_mask8(flow_mod_match->value, flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (matches_8(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (sizeof(uint16_t)):{ if (has_mask){ if (nonstrict_mask16(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (matches_16(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (sizeof(uint32_t)):{ if (has_mask){ if (nonstrict_mask32(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) ){ return false; } } else if (matches_32(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (ETH_ADDR_LEN):{ if (has_mask){ if (nonstrict_ethaddr(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (eth_match(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (sizeof(uint64_t)):{ if (has_mask) { if (nonstrict_mask64(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len) == 0){ return false; } } else if (matches_64(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } case (16):{ if (has_mask){ if (nonstrict_ipv6(flow_mod_match->value,flow_entry_match->value + field_len, flow_entry_match->value,flow_entry_match->value + field_len)== 0){ return false; } } else if (ipv6_match(flow_mod_match->value, flow_entry_match->value) == 0){ return false; } break; } } } if (!ret) return ret; else ret = false; } return true; }
static void set_field(struct packet *pkt, struct ofl_action_set_field *act ) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->valid) { struct packet_fields *iter; /* Search field on the description of the packet. */ HMAP_FOR_EACH_WITH_HASH(iter,struct packet_fields, hmap_node, hash_int(act->field->header,0), &pkt->handle_std->match.match_fields) { struct ip_header *ipv4; struct mpls_header *mpls; struct vlan_header *vlan; uint8_t* tmp; size_t i; /* TODO: Checksum for SCTP and ICMP */ if (iter->header == OXM_OF_IPV4_SRC || iter->header == OXM_OF_IPV4_DST || iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux_old ; aux_old = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux_old, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); if (iter->header == OXM_OF_IP_DSCP) { uint8_t* aux; aux = (uint8_t *)malloc(OXM_LENGTH(iter->header)); memcpy(aux,((uint8_t*)pkt->buffer->data + iter->pos) , OXM_LENGTH(iter->header)); *aux = *aux ^ ((*act->field->value) << 2 ); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , aux , OXM_LENGTH(iter->header)); free(aux); } else if (iter->header == OXM_OF_IP_ECN) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } else { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); } // update TCP/UDP checksum ipv4 = pkt->handle_std->proto->ipv4; if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; if (iter->header == OXM_OF_IPV4_SRC) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_src,htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, ipv4->ip_dst,htonl(*((uint32_t*) act->field->value))); } } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; if (iter->header == OXM_OF_IPV4_SRC) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else if (iter->header == OXM_OF_IPV4_DST) { udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } } if (iter->header == OXM_OF_IP_DSCP || iter->header == OXM_OF_IP_ECN) { uint16_t *aux ; aux = (uint16_t *)malloc(sizeof(uint16_t)); memcpy(aux, ((uint8_t*)pkt->buffer->data + iter->pos - 1) , (2 * OXM_LENGTH(iter->header))); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, *aux_old, *aux); free(aux); } else if (iter->header == OXM_OF_IPV4_SRC) { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_src, htonl(*((uint32_t*) act->field->value))); } else { ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, htonl(*((uint32_t*) act->field->value))); } pkt->handle_std->valid = false; packet_handle_std_validate(pkt->handle_std); free(aux_old); return; } if (iter->header == OXM_OF_TCP_SRC) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_TCP_DST) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_SRC) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, htons(*((uint16_t*) act->field->value))); } else if (iter->header == OXM_OF_UDP_DST) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, htons(*((uint16_t*) act->field->value))); } if (iter->header == OXM_OF_IPV6_SRC || iter->header == OXM_OF_IPV6_DST || iter->header == OXM_OF_ETH_SRC || iter->header == OXM_OF_ETH_DST || iter->header == OXM_OF_ARP_SPA || iter->header == OXM_OF_ARP_TPA || iter->header == OXM_OF_ARP_SHA || iter->header == OXM_OF_ARP_THA) { memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , act->field->value , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_VLAN_VID){ uint16_t vlan_id = *((uint16_t*) act->field->value); vlan = pkt->handle_std->proto->vlan; vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (vlan_id & VLAN_VID_MASK)); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &vlan->vlan_tci , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_VLAN_PCP){ uint8_t vlan_pcp = *((uint8_t*) act->field->value); vlan = pkt->handle_std->proto->vlan; vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_PCP_MASK) | ((vlan_pcp << VLAN_PCP_SHIFT) & VLAN_PCP_MASK)); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &vlan->vlan_tci , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_MPLS_LABEL){ uint32_t mpls_label = *((uint32_t*) act->field->value); mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_LABEL_MASK)) | ntohl((mpls_label << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &mpls->fields , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_MPLS_TC){ mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_TC_MASK)) | ntohl((*act->field->value << MPLS_TC_SHIFT) & MPLS_TC_MASK); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &mpls->fields , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } if (iter->header == OXM_OF_MPLS_BOS){ mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_S_MASK)) | ntohl((*act->field->value << MPLS_S_SHIFT) & MPLS_S_MASK); memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , &mpls->fields , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } tmp = (uint8_t*) malloc(OXM_LENGTH(iter->header)); for (i=0;i<OXM_LENGTH(iter->header);i++) { memcpy(((uint8_t*)tmp + i) , (act->field->value + OXM_LENGTH(iter->header) - i -1 ), 1); } memcpy(((uint8_t*)pkt->buffer->data + iter->pos) , tmp , OXM_LENGTH(iter->header)); pkt->handle_std->valid = false; return; } VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_FIELD action on packet with no corresponding field."); } }
size_t ofl_actions_pack(struct ofl_action_header *src, struct ofp_action_header *dst, uint8_t* data, struct ofl_exp *exp) { dst->type = htons(src->type); memset(dst->pad, 0x00, 4); switch (src->type) { case OFPAT_OUTPUT: { struct ofl_action_output *sa = (struct ofl_action_output *)src; struct ofp_action_output *da = (struct ofp_action_output *)dst; da->len = htons(sizeof(struct ofp_action_output)); da->port = htonl(sa->port); da->max_len = htons(sa->max_len); memset(da->pad, 0x00, 6); return sizeof(struct ofp_action_output); } case OFPAT_COPY_TTL_OUT: case OFPAT_COPY_TTL_IN: { dst->len = htons(sizeof(struct ofp_action_header)); return sizeof(struct ofp_action_header); } case OFPAT_SET_MPLS_TTL: { struct ofl_action_mpls_ttl *sa = (struct ofl_action_mpls_ttl *)src; struct ofp_action_mpls_ttl *da = (struct ofp_action_mpls_ttl *)dst; da->len = htons(sizeof(struct ofp_action_mpls_ttl)); da->mpls_ttl = sa->mpls_ttl; memset(da->pad, 0x00, 3); return sizeof(struct ofp_action_mpls_ttl); } case OFPAT_DEC_MPLS_TTL: { dst->len = htons(sizeof(struct ofp_action_header)); return sizeof(struct ofp_action_header); } case OFPAT_PUSH_VLAN: case OFPAT_PUSH_MPLS: case OFPAT_PUSH_PBB:{ struct ofl_action_push *sa = (struct ofl_action_push *)src; struct ofp_action_push *da = (struct ofp_action_push *)dst; da->len = htons(sizeof(struct ofp_action_push)); da->ethertype = htons(sa->ethertype); memset(da->pad, 0x00, 2); return sizeof(struct ofp_action_push); } case OFPAT_POP_VLAN: case OFPAT_POP_PBB: { struct ofp_action_header *da = (struct ofp_action_header *)dst; da->len = htons(sizeof(struct ofp_action_header)); return sizeof (struct ofp_action_header); } case OFPAT_POP_MPLS: { struct ofl_action_pop_mpls *sa = (struct ofl_action_pop_mpls *)src; struct ofp_action_pop_mpls *da = (struct ofp_action_pop_mpls *)dst; da->len = htons(sizeof(struct ofp_action_pop_mpls)); da->ethertype = htons(sa->ethertype); memset(da->pad, 0x00, 2); return sizeof(struct ofp_action_pop_mpls); } case OFPAT_SET_QUEUE: { struct ofl_action_set_queue *sa = (struct ofl_action_set_queue *)src; struct ofp_action_set_queue *da = (struct ofp_action_set_queue *)dst; da->len = htons(sizeof(struct ofp_action_set_queue)); da->queue_id = htonl(sa->queue_id); return sizeof(struct ofp_action_set_queue); } case OFPAT_GROUP: { struct ofl_action_group *sa = (struct ofl_action_group *)src; struct ofp_action_group *da = (struct ofp_action_group *)dst; da->len = htons(sizeof(struct ofp_action_group)); da->group_id = htonl(sa->group_id); return sizeof(struct ofp_action_group); } case OFPAT_SET_NW_TTL: { struct ofl_action_set_nw_ttl *sa = (struct ofl_action_set_nw_ttl *)src; struct ofp_action_nw_ttl *da = (struct ofp_action_nw_ttl *)dst; da->len = htons(sizeof(struct ofp_action_nw_ttl)); da->nw_ttl = htons(sa->nw_ttl); memset(da->pad, 0x00, 3); return sizeof(struct ofp_action_nw_ttl); } case OFPAT_DEC_NW_TTL: { dst->len = htons(sizeof(struct ofp_action_header)); return sizeof(struct ofp_action_header); } case OFPAT_SET_FIELD: { struct ofl_action_set_field *sa = (struct ofl_action_set_field *) src; struct ofp_action_set_field *da = (struct ofp_action_set_field *) dst; uint32_t header; uint8_t padding_size; da->len = htons(sizeof(struct ofp_action_set_field) + ROUND_UP(OXM_LENGTH(sa->field->header),8)); /*Put OXM header in the field*/ header = htonl(sa->field->header); memcpy(&da->field, &header, 4); switch (OXM_LENGTH(sa->field->header)){ case 1: case 6: case 16: memcpy(data + (sizeof(struct ofp_action_set_field)), sa->field->value,OXM_LENGTH(sa->field->header)); break; case 2:{ uint16_t value = htons(*((uint16_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } case 4:{ uint32_t value = htons(*((uint32_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } case 8:{ uint64_t value = htons(*((uint64_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } } /*padding*/ padding_size = ROUND_UP(OXM_LENGTH(sa->field->header),8) - OXM_LENGTH(sa->field->header); memset(data + (sizeof(struct ofp_action_set_field) + OXM_LENGTH(sa->field->header)), 0, padding_size); return ntohs((da->len)); } case OFPAT_EXPERIMENTER: { if (exp == NULL || exp->act == NULL || exp->act->pack == NULL) { OFL_LOG_WARN(LOG_MODULE, "Trying to pack experimenter, but no callback was given."); return 0; } return exp->act->pack(src, dst); } default: return 0; }; }
static void set_field(struct packet *pkt, struct ofl_action_set_field *act ) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->valid) { /*Field existence is guaranteed by the field pre-requisite on matching */ switch(act->field->header) { case OXM_OF_ETH_DST: { memcpy(pkt->handle_std->proto->eth->eth_dst, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ETH_SRC: { memcpy(pkt->handle_std->proto->eth->eth_src, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ETH_TYPE: { uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); memcpy(&pkt->handle_std->proto->eth->eth_type, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_VLAN_VID: { struct vlan_header *vlan = pkt->handle_std->proto->vlan; /* VLAN existence is no guaranteed by match prerquisite*/ if(vlan != NULL) { uint16_t v = (*(uint16_t*)act->field->value); vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (v & VLAN_VID_MASK)); } break; } case OXM_OF_VLAN_PCP: { struct vlan_header *vlan = pkt->handle_std->proto->vlan; /* VLAN existence is no guaranteed by match prerquisite*/ if(vlan != NULL) { vlan->vlan_tci = (vlan->vlan_tci & ~htons(VLAN_PCP_MASK)) | htons(*act->field->value << VLAN_PCP_SHIFT); break; } } case OXM_OF_IP_DSCP: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | (*act->field->value << 2); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) (ipv4->ip_tos), (uint16_t)tos); ipv4->ip_tos = tos; break; } case OXM_OF_IP_ECN: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | (*act->field->value & IP_ECN_MASK); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) (ipv4->ip_tos), (uint16_t)tos); ipv4->ip_tos = tos; break; } case OXM_OF_IP_PROTO: { pkt->handle_std->proto->ipv4->ip_proto = *act->field->value; break; } case OXM_OF_IPV4_SRC: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; /*Reconstruct TCP or UDP checksum*/ if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum32(tcp->tcp_csum, ipv4->ip_src, *((uint32_t*) act->field->value)); } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_src, *((uint32_t*) act->field->value)); } ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_src, *((uint32_t*) act->field->value)); ipv4->ip_src = *((uint32_t*) act->field->value); break; } case OXM_OF_IPV4_DST: { struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; /*Reconstruct TCP or UDP checksum*/ if (pkt->handle_std->proto->tcp != NULL) { struct tcp_header *tcp = pkt->handle_std->proto->tcp; tcp->tcp_csum = recalc_csum32(tcp->tcp_csum, ipv4->ip_dst, *((uint32_t*) act->field->value)); } else if (pkt->handle_std->proto->udp != NULL) { struct udp_header *udp = pkt->handle_std->proto->udp; udp->udp_csum = recalc_csum32(udp->udp_csum, ipv4->ip_dst, *((uint32_t*) act->field->value)); } ipv4->ip_csum = recalc_csum32(ipv4->ip_csum, ipv4->ip_dst, *((uint32_t*) act->field->value)); ipv4->ip_dst = *((uint32_t*) act->field->value); break; } case OXM_OF_TCP_SRC: { struct tcp_header *tcp = pkt->handle_std->proto->tcp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src,*v); memcpy(&tcp->tcp_src, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_TCP_DST: { struct tcp_header *tcp = pkt->handle_std->proto->tcp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst,*v); memcpy(&tcp->tcp_dst, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_UDP_SRC: { struct udp_header *udp = pkt->handle_std->proto->udp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); memcpy(&udp->udp_src, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_UDP_DST: { struct udp_header *udp = pkt->handle_std->proto->udp; uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); memcpy(&udp->udp_dst, v, OXM_LENGTH(act->field->header)); break; } /*TODO recalculate SCTP checksum*/ case OXM_OF_SCTP_SRC: { uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); memcpy(&pkt->handle_std->proto->sctp->sctp_src, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_SCTP_DST: { uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); memcpy(&pkt->handle_std->proto->sctp->sctp_dst, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ICMPV4_TYPE: case OXM_OF_ICMPV6_TYPE: { pkt->handle_std->proto->icmp->icmp_type = *act->field->value; break; } case OXM_OF_ICMPV4_CODE: case OXM_OF_ICMPV6_CODE: { pkt->handle_std->proto->icmp->icmp_code = *act->field->value; break; } case OXM_OF_ARP_OP: { pkt->handle_std->proto->arp->ar_op = htons(*((uint16_t*) act->field->value)); break; } case OXM_OF_ARP_SPA: { pkt->handle_std->proto->arp->ar_spa = *((uint32_t*) act->field->value); break; } case OXM_OF_ARP_TPA: { pkt->handle_std->proto->arp->ar_tpa = *((uint32_t*) act->field->value); break; } case OXM_OF_ARP_SHA: { memcpy(pkt->handle_std->proto->arp->ar_sha, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ARP_THA: { memcpy(pkt->handle_std->proto->arp->ar_tha, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_SRC: { memcpy(&pkt->handle_std->proto->ipv6->ipv6_src, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_DST: { memcpy(&pkt->handle_std->proto->ipv6->ipv6_dst, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_FLABEL: { struct ipv6_header *ipv6 = (struct ipv6_header*) pkt->handle_std->proto->ipv6; uint32_t v = *((uint32_t*) act->field->value); ipv6->ipv6_ver_tc_fl = (ipv6->ipv6_ver_tc_fl & ~ntohl(IPV6_FLABEL_MASK)) | ntohl(v & IPV6_FLABEL_MASK); break; } /*IPV6 Neighbor Discovery */ case OXM_OF_IPV6_ND_TARGET: { struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; uint8_t *data = (uint8_t*)icmp; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct icmp_header) + 4; memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); break; } case OXM_OF_IPV6_ND_SLL: { struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) icmp + sizeof(struct icmp_header); uint8_t *data = (uint8_t*) opt; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct ipv6_nd_header); if(opt->type == ND_OPT_SLL) { memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); } break; } case OXM_OF_IPV6_ND_TLL: { struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) icmp + sizeof(struct icmp_header); uint8_t *data = (uint8_t*) opt; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct ipv6_nd_header); if(opt->type == ND_OPT_TLL) { memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); } break; } case OXM_OF_MPLS_LABEL: { struct mpls_header *mpls = pkt->handle_std->proto->mpls; uint32_t v = *((uint32_t*) act->field->value); mpls->fields = (mpls->fields & ~ntohl(MPLS_LABEL_MASK)) | ntohl((v << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK); break; } case OXM_OF_MPLS_TC: { struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_TC_MASK)) | ntohl((*act->field->value << MPLS_TC_SHIFT) & MPLS_TC_MASK); break; } case OXM_OF_MPLS_BOS: { struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_S_MASK)) | ntohl((*act->field->value << MPLS_S_SHIFT) & MPLS_S_MASK); break; } case OXM_OF_PBB_ISID : { struct pbb_header *pbb = pkt->handle_std->proto->pbb; uint32_t v = *((uint32_t*) act->field->value); pbb->id = (pbb->id & ~ntohl(PBB_ISID_MASK)) | ntohl(v & PBB_ISID_MASK); break; } default: VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to set unknow field."); break; } pkt->handle_std->valid = false; return; } }
/* Returns true if the fields in *packet matches the flow entry in *flow_match */ bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet) { struct ofl_match_tlv *f; struct ofl_match_tlv *packet_f; bool has_mask; int field_len; int packet_header; uint8_t *flow_val, *flow_mask=0; uint8_t *packet_val; if (flow_match->header.length == 0) { return true; } /* Loop over the flow entry's match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields) { /* Check presence of match field in packet */ has_mask = OXM_HASMASK(f->header); field_len = OXM_LENGTH(f->header); packet_header = f->header; flow_val = f->value; if (has_mask) { /* Clear the has_mask bit and divide the field_len by two in the packet field header */ field_len /= 2; packet_header &= 0xfffffe00; packet_header |= field_len; flow_mask = f->value + field_len; } char *f_str = ofl_structs_oxm_tlv_to_string(f); free(f_str); /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { if (f->header==OXM_OF_VLAN_VID && *((uint16_t *) f->value)==OFPVID_NONE) { /* There is no VLAN tag, as required */ continue; } return false; } /* Compare the flow and packet field values, considering the mask, if any */ packet_val = packet_f->value; switch (field_len) { case 1: if (has_mask) { if (!match_mask8(flow_val, flow_mask, packet_val)) return false; } else { if (!match_8(flow_val, packet_val)) return false; } break; case 2: switch (packet_header) { case OXM_OF_VLAN_VID: { /* Special handling for VLAN ID */ uint16_t flow_vlan_id = *((uint16_t *) flow_val); if (flow_vlan_id == OFPVID_NONE) { /* Packet has a VLAN tag when none should be there */ return false; } else if (flow_vlan_id == OFPVID_PRESENT) { /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ if (!match_16(flow_val, packet_val)) return false; } break; } case OXM_OF_IPV6_EXTHDR: { /* Special handling for IPv6 Extension header */ uint16_t flow_eh = *((uint16_t *) flow_val); uint16_t packet_eh = *((uint16_t *) packet_val); if ((flow_eh & packet_eh) != flow_eh) { /* The packet doesn't have all extension headers specified in the flow */ return false; } break; } default: if (has_mask) { if (!match_mask16(flow_val, flow_mask, packet_val)) return false; } else { if (!match_16(flow_val, packet_val)) return false; } break; } break; case 4: if (has_mask) { if (!match_mask32(flow_val, flow_mask, packet_val)) return false; } else { if (!match_32(flow_val, packet_val)) return false; } break; case 6: if (has_mask) { if (!match_mask48(flow_val, flow_mask, packet_val)) return false; } else { if (!match_48(flow_val, packet_val)) return false; } break; case 8: if (has_mask) { if (!match_mask64(flow_val, flow_mask, packet_val)) return false; } else { if (!match_64(flow_val, packet_val)) return false; } break; case 16: if (has_mask) { if (!match_mask128(flow_val, flow_mask, packet_val)) return false; } else { if (!match_128(flow_val, packet_val)) return false; } break; default: /* Should never happen */ break; } } /* If we get here, all match fields in the flow entry matched the packet */ return true; }
bool packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ struct ofl_match_tlv *f; struct packet_fields *packet_f; bool ret = false; if (flow_match->header.length == 0){ return true; } /*TODO: Possible combinations of VLAN_ID and masks */ HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, hmap_node,hash_int(OXM_OF_VLAN_VID, 0), &flow_match->match_fields){ uint16_t *matchv = (uint16_t*) f->value; /* Check if the field is present in the packet */ HMAP_FOR_EACH_WITH_HASH(packet_f, struct packet_fields, hmap_node, hash_int(OXM_OF_VLAN_VID, 0), &packet->match_fields){ /* Do not match packets with a VLAN Tag */ if (*matchv == OFPVID_NONE && !OXM_HASMASK(f->header)) return false; ret = true; } if ((*matchv == OFPVID_PRESENT) & (OXM_HASMASK(f->header))){ uint16_t *maskv = (uint16_t*) f->value + 2; if (*maskv == OFPVID_PRESENT && !ret ) return false; } } /* Loop through the match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields){ /* Check if the field is present in the packet */ HMAP_FOR_EACH_WITH_HASH(packet_f, struct packet_fields, hmap_node, hash_int(f->header, 0), &packet->match_fields){ int field_len = OXM_LENGTH(f->header); bool has_mask = OXM_HASMASK(f->header); ret = true; switch (field_len){ case (sizeof(uint8_t)):{ if (has_mask){ if (pkt_mask8(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_8(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint16_t)):{ if (has_mask){ if (pkt_mask16(f->value,f->value+ field_len, packet_f->value) == 0){ return false; } } else { if (pkt_match_16(f->value, packet_f->value) == 0){ return false; } } break; } case (sizeof(uint32_t)):{ if (has_mask){ if (f->header == OXM_OF_IPV4_DST || f->header == OXM_OF_IPV4_SRC ||f->header == OXM_OF_ARP_SPA || f->header == OXM_OF_ARP_TPA){ if (matches_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (pkt_mask32(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (f->header == OXM_OF_IPV4_DST || f->header == OXM_OF_IPV4_SRC ||f->header == OXM_OF_ARP_SPA || f->header == OXM_OF_ARP_TPA){ if (matches_32(f->value, packet_f->value) == 0){ return false; } } else if (pkt_match_32(f->value, packet_f->value) == 0){ return false; } break; } case (ETH_ADDR_LEN):{ if (has_mask){ if (eth_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (eth_match(f->value, packet_f->value) == 0){ return false; } break; } case (sizeof(uint64_t)):{ if (has_mask) { if (pkt_mask64(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (matches_64(f->value, packet_f->value) == 0){ return false; } break; } case (16):{ if (has_mask){ if (ipv6_mask(f->value,f->value + field_len, packet_f->value) == 0){ return false; } } else if (ipv6_match(f->value, packet_f->value) == 0){ return false; } break; } } } if (!ret) return ret; else ret = false; } return true; }
size_t ofl_actions_pack(struct ofl_action_header *src, struct ofp_action_header *dst, uint8_t* data, struct ofl_exp *exp) { dst->type = htons(src->type); memset(dst->pad, 0x00, 4); switch (src->type) { case OFPAT_OUTPUT: { struct ofl_action_output *sa = (struct ofl_action_output *)src; struct ofp_action_output *da = (struct ofp_action_output *)dst; da->len = htons(sizeof(struct ofp_action_output)); da->port = htonl(sa->port); da->max_len = htons(sa->max_len); memset(da->pad, 0x00, 6); return sizeof(struct ofp_action_output); } case OFPAT_COPY_TTL_OUT: case OFPAT_COPY_TTL_IN: { dst->len = htons(sizeof(struct ofp_action_header)); return sizeof(struct ofp_action_header); } case OFPAT_SET_MPLS_TTL: { struct ofl_action_mpls_ttl *sa = (struct ofl_action_mpls_ttl *)src; struct ofp_action_mpls_ttl *da = (struct ofp_action_mpls_ttl *)dst; da->len = htons(sizeof(struct ofp_action_mpls_ttl)); da->mpls_ttl = sa->mpls_ttl; memset(da->pad, 0x00, 3); return sizeof(struct ofp_action_mpls_ttl); } case OFPAT_DEC_MPLS_TTL: { dst->len = htons(sizeof(struct ofp_action_header)); return sizeof(struct ofp_action_header); } case OFPAT_PUSH_VLAN: case OFPAT_PUSH_MPLS: case OFPAT_PUSH_PBB:{ struct ofl_action_push *sa = (struct ofl_action_push *)src; struct ofp_action_push *da = (struct ofp_action_push *)dst; da->len = htons(sizeof(struct ofp_action_push)); da->ethertype = htons(sa->ethertype); memset(da->pad, 0x00, 2); return sizeof(struct ofp_action_push); } case OFPAT_POP_VLAN: case OFPAT_POP_PBB: { struct ofp_action_header *da = (struct ofp_action_header *)dst; da->len = htons(sizeof(struct ofp_action_header)); return sizeof (struct ofp_action_header); } case OFPAT_POP_MPLS: { struct ofl_action_pop_mpls *sa = (struct ofl_action_pop_mpls *)src; struct ofp_action_pop_mpls *da = (struct ofp_action_pop_mpls *)dst; da->len = htons(sizeof(struct ofp_action_pop_mpls)); da->ethertype = htons(sa->ethertype); memset(da->pad, 0x00, 2); return sizeof(struct ofp_action_pop_mpls); } case OFPAT_SET_QUEUE: { struct ofl_action_set_queue *sa = (struct ofl_action_set_queue *)src; struct ofp_action_set_queue *da = (struct ofp_action_set_queue *)dst; da->len = htons(sizeof(struct ofp_action_set_queue)); da->queue_id = htonl(sa->queue_id); return sizeof(struct ofp_action_set_queue); } case OFPAT_GROUP: { struct ofl_action_group *sa = (struct ofl_action_group *)src; struct ofp_action_group *da = (struct ofp_action_group *)dst; da->len = htons(sizeof(struct ofp_action_group)); da->group_id = htonl(sa->group_id); return sizeof(struct ofp_action_group); } case OFPAT_SET_NW_TTL: { struct ofl_action_set_nw_ttl *sa = (struct ofl_action_set_nw_ttl *)src; struct ofp_action_nw_ttl *da = (struct ofp_action_nw_ttl *)dst; da->len = htons(sizeof(struct ofp_action_nw_ttl)); da->nw_ttl = sa->nw_ttl; memset(da->pad, 0x00, 3); return sizeof(struct ofp_action_nw_ttl); } case OFPAT_DEC_NW_TTL: { dst->len = htons(sizeof(struct ofp_action_header)); return sizeof(struct ofp_action_header); } case OFPAT_SET_FIELD: { struct ofl_action_set_field *sa = (struct ofl_action_set_field *) src; struct ofp_action_set_field *da = (struct ofp_action_set_field *) dst; uint32_t header; uint8_t padding_size; da->len = htons(sizeof(struct ofp_action_set_field) + ROUND_UP(OXM_LENGTH(sa->field->header),8)); /*Put OXM header in the field*/ header = htonl(sa->field->header); memcpy(&da->field, &header, 4); /* For OFDPA2.0 */ if(0xFFFF == OXM_VENDOR(sa->field->header)) /* exp */ { struct OFDPA_ofl_match_exp_tlv* ofdpa_exp_tlv_p = (struct OFDPA_ofl_match_exp_tlv*)sa->field; uint32_t experimenter_v = htonl(ofdpa_exp_tlv_p->experimenter); uint16_t exp_type_v = htons(ofdpa_exp_tlv_p->exp_type); uint8_t length = OXM_LENGTH(sa->field->header); uint8_t offset_len = sizeof(struct ofp_action_set_field); length -= sizeof(experimenter_v); length -= sizeof(exp_type_v); memcpy(data + offset_len, &experimenter_v, sizeof(experimenter_v)); offset_len += sizeof(experimenter_v); memcpy(data + offset_len, &exp_type_v, sizeof(exp_type_v)); offset_len += sizeof(exp_type_v); switch(length) { case (sizeof(uint8_t)): memcpy(data + offset_len, ofdpa_exp_tlv_p->exp_data_p, sizeof(uint8_t)); break; case (sizeof(uint16_t)): { uint16_t value = htons(*((uint16_t*) ofdpa_exp_tlv_p->exp_data_p)); memcpy(data + offset_len, &value, sizeof(value)); break; } case (sizeof(uint32_t)): { uint32_t value = htonl(*((uint32_t*) ofdpa_exp_tlv_p->exp_data_p)); memcpy(data + offset_len, &value, sizeof(value)); break; } case (sizeof(uint64_t)): { uint64_t value = hton64(*((uint64_t*) ofdpa_exp_tlv_p->exp_data_p)); memcpy(data + offset_len, &value, sizeof(value)); break; } } /*padding*/ padding_size = ROUND_UP(OXM_LENGTH(sa->field->header),8) - OXM_LENGTH(sa->field->header); memset(data + (sizeof(struct ofp_action_set_field) + OXM_LENGTH(sa->field->header)), 0, padding_size); return ntohs((da->len)); } /* End of OFDPA2.0 */ switch (OXM_LENGTH(sa->field->header)){ case 1: case 6: case 12: case 16: memcpy(data + sizeof(struct ofp_action_set_field), sa->field->value,OXM_LENGTH(sa->field->header)); break; case 2:{ uint16_t value = htons(*((uint16_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } case 4:{ uint16_t value1,value2; uint32_t value; uint8_t field = OXM_FIELD(sa->field->header); if( field != 11 && field != 12 && field != 22 && field != 23) value = htonl(*((uint32_t*) sa->field->value)); else value = *((uint32_t*) sa->field->value); if(field == 6){ value1 = value >> 16; value2 = value & 0xffff; value = (((uint32_t)value2) << 16)+(uint32_t)value1; } memcpy(data + (sizeof(struct ofp_action_set_field)), &value, OXM_LENGTH(sa->field->header)); break; } case 8:{ uint64_t value; uint8_t field = OXM_FIELD(sa->field->header); if(field == 38) /* This is for tunnel_id */ value = hton64(*((uint64_t *) sa->field->value)); else value = htons(*((uint64_t *) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } } /*padding*/ padding_size = ROUND_UP(OXM_LENGTH(sa->field->header),8) - OXM_LENGTH(sa->field->header); memset(data + (sizeof(struct ofp_action_set_field) + OXM_LENGTH(sa->field->header)), 0, padding_size); return ntohs((da->len)); } case OFPAT_EXPERIMENTER: { if (exp == NULL || exp->act == NULL || exp->act->pack == NULL) { OFL_LOG_WARN(LOG_MODULE, "Trying to pack experimenter, but no callback was given."); return 0; } return exp->act->pack(src, dst); } default: return 0; };
/* Flow entry (a) matches flow entry (b) non-strictly if (a) matches whenever (b) matches. * Thus, flow (a) must not have more match fields than (b) and all match fields in (a) must * be equal or narrower in (b). * NOTE: Handling of bitmasked fields is not specified. In this implementation * a masked field of (a) matches the field of (b) if all masked bits of (b) are * also masked in (a), and for each unmasked bits of (b) , the bit is either * masked in (a), or is set to the same value in both matches. * */ bool match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) { struct ofl_match_tlv *flow_mod_match; struct ofl_match_tlv *flow_entry_match; int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; bool has_mask; /* Flow a is fully wildcarded */ if (!a->header.length) return true; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(flow_mod_match, struct ofl_match_tlv, hmap_node, &a->match_fields) { /* Check presence of match field in flow entry */ flow_entry_match = oxm_match_lookup(flow_mod_match->header, b); if (!flow_entry_match) { return false; } /* At this point match length and has_mask are equal */ has_mask = OXM_HASMASK(flow_mod_match->header); field_len = OXM_LENGTH(flow_mod_match->header); flow_mod_val = flow_mod_match->value; flow_entry_val = flow_entry_match->value; if (has_mask) { field_len /= 2; flow_mod_mask = flow_mod_match->value + field_len; flow_entry_mask = flow_entry_match->value + field_len; } switch (field_len) { case 1: if (has_mask) { if (!nonstrict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_8(flow_mod_val, flow_entry_val)) return false; } break; case 2: if (has_mask) { if (!nonstrict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_16(flow_mod_val, flow_entry_val)) return false; } break; case 4: if (has_mask) { if (!nonstrict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_32(flow_mod_val, flow_entry_val)) return false; } break; case 6: if (has_mask) { if (!nonstrict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_48(flow_mod_val, flow_entry_val)) return false; } break; case 8: if (has_mask) { if (!nonstrict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_64(flow_mod_val, flow_entry_val)) return false; } break; case 16: if (has_mask) { if (!nonstrict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } else { if (!match_128(flow_mod_val, flow_entry_val)) return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* HMAP_FOR_EACH */ /* If we get here, all match fields in flow a were equal or wider than the ones in b */ /* It doesn't matter if there are further fields in b */ return true; }
bool match_std_overlap(struct ofl_match *a, struct ofl_match *b) { uint64_t all_mask[2] = {0, 0}; struct ofl_match_tlv *f_a; struct ofl_match_tlv *f_b; int header, header_m; int field_len; uint8_t *val_a, *mask_a; uint8_t *val_b, *mask_b; /* Loop through the match fields in flow entry a */ HMAP_FOR_EACH(f_a, struct ofl_match_tlv, hmap_node, &a->match_fields) { field_len = OXM_LENGTH(f_a->header); val_a = f_a->value; if (OXM_HASMASK(f_a->header)) { field_len /= 2; header = (f_a->header & 0xfffffe00) | field_len; header_m = f_a->header; mask_a = f_a->value + field_len; } else { header = f_a->header; header_m = (f_a->header & 0xfffffe00) | 0x100 | (field_len << 1); /* Set a dummy mask with all bits set to 0 (valid) */ mask_a = (uint8_t *) all_mask; } /* Check presence of corresponding match field in flow entry b * Need to check for both masked and non-masked field */ f_b = oxm_match_lookup(header, b); if (!f_b) f_b = oxm_match_lookup(header_m, b); if (f_b) { val_b = f_b->value; if (OXM_HASMASK(f_b->header)) { mask_b = f_b->value + field_len; } else { /* Set a dummy mask with all bits set to 0 (valid) */ mask_b = (uint8_t *) all_mask; } switch (field_len) { case 1: if (incompatible_8(val_a, val_b, mask_a, mask_b)) { return false; } break; case 2: if (incompatible_16(val_a, val_b, mask_a, mask_b)) { return false; } break; case 4: if (incompatible_32(val_a, val_b, mask_a, mask_b)) { return false; } break; case 6: if (incompatible_48(val_a, val_b, mask_a, mask_b)) { return false; } break; case 8: if (incompatible_64(val_a, val_b, mask_a, mask_b)) { return false; } break; case 16: if (incompatible_128(val_a, val_b, mask_a, mask_b)) { return false; } break; default: /* Should never happen */ break; } /* switch (field_len) */ } /* if (f_b) */ } /* HMAP_FOR_EACH */ /* If we get here, none of the common match fields in a and b were found incompatible. * The flow entries overlap */ return true; }
void ofl_action_print(FILE *stream, struct ofl_action_header *act, struct ofl_exp *exp) { ofl_action_type_print(stream, act->type); switch (act->type) { case OFPAT_OUTPUT: { struct ofl_action_output *a = (struct ofl_action_output *)act; fprintf(stream, ",{\"port\":"); ofl_port_print(stream, a->port); if (a->port == OFPP_CONTROLLER) { fprintf(stream, ", \"mlen\":%u}", a->max_len); } else { fprintf(stream, "}"); } break; } case OFPAT_SET_FIELD:{ size_t size; struct ofl_action_set_field *a = (struct ofl_action_set_field *)act; fprintf(stream, ",{"); size = 4 + OXM_LENGTH(a->field->header); print_oxm_tlv(stream, a->field, &size); fprintf(stream, "}"); break; } case OFPAT_COPY_TTL_OUT: case OFPAT_COPY_TTL_IN: { break; } case OFPAT_SET_MPLS_TTL: { struct ofl_action_mpls_ttl *a = (struct ofl_action_mpls_ttl *)act; fprintf(stream, ",{\"ttl\":%u}", a->mpls_ttl); break; } case OFPAT_DEC_MPLS_TTL: { break; } case OFPAT_PUSH_VLAN: case OFPAT_PUSH_MPLS: case OFPAT_PUSH_PBB:{ struct ofl_action_push *a = (struct ofl_action_push *)act; fprintf(stream, ",{\"eth\":\"0x%04"PRIx16"\"}", a->ethertype); break; } case OFPAT_POP_VLAN: case OFPAT_POP_PBB: { break; } case OFPAT_POP_MPLS: { struct ofl_action_pop_mpls *a = (struct ofl_action_pop_mpls *)act; fprintf(stream, ",{\"eth\":\"0x%04"PRIx16"\"}", a->ethertype); break; } case OFPAT_SET_QUEUE: { struct ofl_action_set_queue *a = (struct ofl_action_set_queue *)act; fprintf(stream, ",{\"q\":"); ofl_queue_print(stream, a->queue_id); fprintf(stream, "}"); break; } case OFPAT_GROUP: { struct ofl_action_group *a = (struct ofl_action_group *)act; fprintf(stream, ",{\"id\":"); ofl_group_print(stream, a->group_id); fprintf(stream, "}"); break; } case OFPAT_SET_NW_TTL: { struct ofl_action_set_nw_ttl *a = (struct ofl_action_set_nw_ttl *)act; fprintf(stream, ",{\"ttl\":%u}", a->nw_ttl); break; } case OFPAT_DEC_NW_TTL: { break; } case OFPAT_EXPERIMENTER: { if (exp == NULL || exp->act == NULL || exp->act->to_string == NULL) { struct ofl_action_experimenter *a = (struct ofl_action_experimenter *)act; fprintf(stream, ",{\"id\":\"0x%"PRIx32"\"}", a->experimenter_id); } else { char *c = exp->act->to_string(act); fprintf(stream, "%s", c); free (c); } break; } } }