Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
0
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;
    };
Exemplo n.º 3
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_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;
}
Exemplo n.º 4
0
/* 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;
}
Exemplo n.º 5
0
/* 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;
}
Exemplo n.º 6
0
void
ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f)
{
#ifdef OTN_SUPPORT
                uint16_t oxm_class = OXM_VENDOR(f->header);
                if (oxm_class == 0xffff) {
                  uint8_t field = OXM_FIELD(f->header);
                  if (field == OFPXMT_TLAB_GMPLS_SWCAPENCTYPE){
                         ofp_oxm_tlab_gmpls_swcapenctype_t *data=(ofp_oxm_tlab_gmpls_swcapenctype_t *)f->value;
                            fprintf(stream, "gmpls_swcapenctype={experimenter_id=\"0x%2x\"",ntohl( data->experimenter));
                            fprintf(stream, ", gmpls_swcap=\"0x%x\"", data->swcap);
                            fprintf(stream, ", gmpls_enctype=\"0x%x\"", data->enctype);
                            fprintf(stream, "} ");
                  }else if (field == OFPXMT_TLAB_GMPLS_SIGTYPE){
                         ofp_oxm_tlab_gmpls_sigtype_t *data=(ofp_oxm_tlab_gmpls_sigtype_t *)f->value;
                            fprintf(stream, "gmpls_sigtype={experimenter_id=\"0x%2x\"", ntohl(data->experimenter));
                            fprintf(stream, ", gmpls_swcap=\"0x%2x\"", data->sig_type);
                            fprintf(stream, "} ");
                  }else if (field == OFPXMT_TLAB_GMPLS_LABEL){
                         ofp_oxm_tlab_gmpls_label_t *data=(ofp_oxm_tlab_gmpls_label_t *)f->value;
                            uint32_t *label = (uint32_t *) data->label;
                            fprintf(stream, "gmpls_label={experimenter_id=\"0x%2x\"", ntohl(data->experimenter));
                            fprintf(stream, ", gmpls_label=\"0x%2x\"",ntohl( *label));
                            fprintf(stream, "} ");
                  }

                } else {
#endif

	uint8_t field = OXM_FIELD(f->header);

	switch (field) {

		case OFPXMT_OFB_IN_PORT:
			fprintf(stream, "in_port=\"%d\"", *((uint32_t*) f->value));
			break;
		case OFPXMT_OFB_IN_PHY_PORT:
			fprintf(stream, "in_phy_port=\"%d\"", *((uint32_t*) f->value));
			break;
		case OFPXMT_OFB_VLAN_VID: {
			uint16_t v = *((uint16_t *) f->value);
			if (v == OFPVID_NONE)
				fprintf(stream, "vlan_vid= none");
			else if (v == OFPVID_PRESENT && OXM_HASMASK(f->header))
				fprintf(stream, "vlan_vid= any");
			else
				fprintf(stream, "vlan_vid=\"%d\"",v & VLAN_VID_MASK);
			break;
		}
		case OFPXMT_OFB_VLAN_PCP:
			fprintf(stream, "vlan_pcp=\"%d\"", *f->value & 0x7);
			break;
		case OFPXMT_OFB_ETH_TYPE:
			fprintf(stream, "eth_type=\"0x%x\"",  *((uint16_t *) f->value));
			break;
		case OFPXMT_OFB_TCP_SRC:
			fprintf(stream, "tcp_src=\"%d\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_TCP_DST:
			fprintf(stream, "tcp_dst=\"%d\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_UDP_SRC:
			fprintf(stream, "udp_src=\"%d\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_UDP_DST:
			fprintf(stream, "udp_dst=\"%d\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_SCTP_SRC:
			fprintf(stream, "sctp_src=\"%d\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_SCTP_DST:
			fprintf(stream, "sctp_dst=\"%d\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_ETH_SRC:
			fprintf(stream, "eth_src=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", eth_src_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6));
			}
			break;
		case OFPXMT_OFB_ETH_DST:
			fprintf(stream, "eth_dst=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", eth_dst_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6));
			}
			break;
		case OFPXMT_OFB_IPV4_DST:
			fprintf(stream, "ipv4_dst=\""IP_FMT"\"", IP_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", ipv4_dst_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4));
			}
			break;
		case OFPXMT_OFB_IPV4_SRC:
			fprintf(stream, "ipv4_src=\""IP_FMT"\"", IP_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", ipv4_src_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4));
			}
			break;
		case OFPXMT_OFB_IP_PROTO:
			fprintf(stream, "ip_proto=\"%d\"", *f->value);
			break;
		case OFPXMT_OFB_IP_DSCP:
			fprintf(stream, "ip_dscp=\"%d\"", *f->value & 0x3f);
			break;
		case OFPXMT_OFB_IP_ECN:
			fprintf(stream, "ip_ecn=\"%d\"", *f->value & 0x3);
			break;
		case OFPXMT_OFB_ICMPV4_TYPE:
			fprintf(stream, "icmpv4_type= \"%d\"", *f->value);
			break;
		case OFPXMT_OFB_ICMPV4_CODE:
			fprintf(stream, "icmpv4_code=\"%d\"", *f->value);
			break;
		case OFPXMT_OFB_ARP_SHA:
			fprintf(stream, "arp_sha=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", arp_sha_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6));
			}
			break;
		case OFPXMT_OFB_ARP_THA:
			fprintf(stream, "arp_tha=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", arp_tha_mask=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value + 6));
			}
			break;
		case OFPXMT_OFB_ARP_SPA:
			fprintf(stream, "arp_spa=\""IP_FMT"\"", IP_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", arp_sha_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4));
			}
			break;
		case OFPXMT_OFB_ARP_TPA:
			fprintf(stream, "arp_tpa=\""IP_FMT"\"", IP_ARGS(f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", arp_tpa_mask=\""IP_FMT"\"", IP_ARGS(f->value + 4));
			}
			break;
		case OFPXMT_OFB_ARP_OP:
			fprintf(stream, "arp_op=\"0x%x\"", *((uint16_t*) f->value));
			break;
		case OFPXMT_OFB_IPV6_SRC: {
			char addr_str[INET6_ADDRSTRLEN];
			inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN);
			fprintf(stream, "nw_src_ipv6=\"%s\"", addr_str);
			if (OXM_HASMASK(f->header)) {
				inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN);
				fprintf(stream, ", nw_src_ipv6_mask=\"%s\"", addr_str);
			}
			break;
		}
		case OFPXMT_OFB_IPV6_DST: {
			char addr_str[INET6_ADDRSTRLEN];
			inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN);
			fprintf(stream, "nw_dst_ipv6=\"%s\"", addr_str);
			if (OXM_HASMASK(f->header)) {
				inet_ntop(AF_INET6, f->value + 16, addr_str, INET6_ADDRSTRLEN);
				fprintf(stream, ", nw_dst_ipv6_mask=\"%s\"", addr_str);
			}
			break;
		}
		case OFPXMT_OFB_IPV6_ND_TARGET: {
			char addr_str[INET6_ADDRSTRLEN];
			inet_ntop(AF_INET6, f->value, addr_str, INET6_ADDRSTRLEN);
			fprintf(stream, "ipv6_nd_target=\"%s\"", addr_str);
			break;
		}
		case OFPXMT_OFB_IPV6_ND_SLL:
			fprintf(stream, "ipv6_nd_sll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value));
			break;
		case OFPXMT_OFB_IPV6_ND_TLL:
			fprintf(stream, "ipv6_nd_tll=\""ETH_ADDR_FMT"\"", ETH_ADDR_ARGS(f->value));
			break;
		case OFPXMT_OFB_IPV6_FLABEL:
			fprintf(stream, "ipv6_flow_label=\"%d\"", *((uint32_t*) f->value) & 0x000fffff);
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", ipv6_flow_label_mask=\"%d\"", *((uint32_t*) (f->value+4)));
			}
			break;
		case OFPXMT_OFB_ICMPV6_TYPE:
			fprintf(stream, "icmpv6_type=\"%d\"", *f->value);
			break;
		case OFPXMT_OFB_ICMPV6_CODE:
			fprintf(stream, "icmpv6_code=\"%d\"", *f->value);
			break;
		case OFPXMT_OFB_MPLS_LABEL:
			fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & 0x000fffff);
			break;
		case OFPXMT_OFB_MPLS_TC:
			fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3);
			break;
		case OFPXMT_OFB_MPLS_BOS:
			fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0xfe);
			break;
		case OFPXMT_OFB_METADATA:
			fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", metadata_mask=\"0x%llx\"", *((uint64_t*)(f->value+8)));
			}
			break;
		case OFPXMT_OFB_PBB_ISID   :
			fprintf(stream, "pbb_isid=\"%d\"", *((uint32_t*) f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", pbb_isid_mask=\"%d\"", *((uint32_t*)(f->value+4)));
			}
			break;
		case OFPXMT_OFB_TUNNEL_ID:
			fprintf(stream, "tunnel_id=\"%lld\"", *((uint64_t*) f->value));
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", tunnel_id_mask=\"%lld\"", *((uint64_t*)(f->value+8)));
			}
			break;
		case OFPXMT_OFB_IPV6_EXTHDR:
			fprintf(stream, "ext_hdr=\"");
			ofl_ipv6_ext_hdr_print(stream, *((uint16_t*) f->value));
			fprintf(stream, "\"");
			if (OXM_HASMASK(f->header)) {
				fprintf(stream, ", ext_hdr_mask=\"0x%x\"", *((uint16_t*)(f->value+4)));
			}
			break;
		default:
			fprintf(stream, "unknown type %d", field);
	}
#ifdef OTN_SUPPORT
    }
#endif
}
Exemplo n.º 7
0
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;
            uint32_t tmp_header = 0;
            uint8_t *value;

            sa = (struct ofp_action_set_field*) src;
            da = (struct ofl_action_set_field *)malloc(sizeof(struct ofl_action_set_field));

            memcpy(&tmp_header, sa->field, 4);
            tmp_header = ntohl(tmp_header);

/* For OFDPA2.0
 */
            if(0xFFFF == OXM_VENDOR(tmp_header))  /* exp */
            {
                struct OFDPA_ofl_match_exp_tlv *ofdpa_exp_tlv_p = malloc(sizeof(struct OFDPA_ofl_match_exp_tlv)+OXM_LENGTH(tmp_header));
                uint32_t experimenter_v = 0;
                uint16_t exp_type_v = 0;
                uint8_t length = OXM_LENGTH(tmp_header);
                uint8_t get_offset_len = sizeof(struct ofp_action_set_field);
                uint8_t set_offset_len = 0;

                ofdpa_exp_tlv_p->header = tmp_header;

                memcpy(&experimenter_v, (uint8_t *) src + get_offset_len, 4);
                experimenter_v = ntohl(experimenter_v);
                ofdpa_exp_tlv_p->experimenter = experimenter_v;
                get_offset_len += 4;

                memcpy(&exp_type_v, (uint8_t *) src + get_offset_len, 2);
                exp_type_v = ntohs(exp_type_v);
                ofdpa_exp_tlv_p->exp_type = exp_type_v;
                get_offset_len += 2;

                set_offset_len = 6 /* exp + type */;
                length -= 6;

                switch(length)
                {
                    case (sizeof(uint8_t)):
                    {
                        uint8_t *u8_v_p = xmalloc(sizeof(uint8_t));

                        memcpy(u8_v_p, (uint8_t *) src + get_offset_len, 1);
                        ofdpa_exp_tlv_p->exp_data_p = (uint8_t*) u8_v_p;
                        break;
                    }

                    case (sizeof(uint16_t)):
                    {
                        uint16_t *u16_v_p = xmalloc(sizeof(uint16_t));

                        memcpy(u16_v_p, (uint8_t *) src + get_offset_len, 2);
                        *u16_v_p = ntohs(*u16_v_p);
                        ofdpa_exp_tlv_p->exp_data_p = (uint8_t*) u16_v_p;
                        break;
                    }

                    case (sizeof(uint32_t)):
                    {
                        uint32_t *u32_v_p = xmalloc(sizeof(uint32_t));

                        memcpy(u32_v_p, (uint8_t *) src + get_offset_len, 4);
                        *u32_v_p = ntohl(*u32_v_p);
                        ofdpa_exp_tlv_p->exp_data_p = (uint8_t*) u32_v_p;
                        break;
                    }

                    case (sizeof(uint64_t)):
                    {
                        uint64_t *u64_v_p = xmalloc(sizeof(uint64_t));

                        memcpy(u64_v_p, (uint8_t *) src + get_offset_len, 8);
                        *u64_v_p = ntohl(*u64_v_p);
                        ofdpa_exp_tlv_p->exp_data_p = (uint8_t*) u64_v_p;
                        break;
                    }
                }

                da->field = (struct ofl_match_tlv*) ofdpa_exp_tlv_p;
                *len -= ROUND_UP(ntohs(src->len),8);
                *dst = (struct ofl_action_header *)da;
                break;
            }
/* End of OFDPA2.0
 */
            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);
            da->field->value = malloc(OXM_LENGTH(da->field->header));
            value = (uint8_t *) src + sizeof (struct ofp_action_set_field);

            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;
}