static ofl_err ofl_msg_unpack_packet_in(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { struct ofp_packet_in *sp; struct ofl_msg_packet_in *dp; if (*len < sizeof(struct ofp_packet_in)) { OFL_LOG_WARN(LOG_MODULE, "Received PACKET_IN message has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } sp = (struct ofp_packet_in *)src; if (ntohl(sp->in_port) == 0 || (ntohl(sp->in_port) > OFPP_MAX && ntohl(sp->in_port) != OFPP_LOCAL)) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(sp->in_port)); OFL_LOG_WARN(LOG_MODULE, "Received PACKET_IN message has invalid in_port (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } if (sp->table_id == 0xff) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ts = ofl_table_to_string(sp->table_id); OFL_LOG_WARN(LOG_MODULE, "Received PACKET_IN has invalid table_id (%s).", ts); free(ts); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } *len -= sizeof(struct ofp_packet_in); dp = (struct ofl_msg_packet_in *)malloc(sizeof(struct ofl_msg_packet_in)); dp->buffer_id = ntohl(sp->buffer_id); dp->in_port = ntohl(sp->in_port); dp->in_phy_port = ntohl(sp->in_phy_port); dp->total_len = ntohs(sp->total_len); dp->reason = (enum ofp_packet_in_reason)sp->reason; dp->table_id = sp->table_id; dp->data_length = *len; dp->data = *len > 0 ? (uint8_t *)memcpy(malloc(*len), sp->data, *len) : NULL; *len = 0; *msg = (struct ofl_msg_header *)dp; return 0; }
ofl_err ofl_structs_queue_stats_unpack(struct ofp_queue_stats *src, size_t *len, struct ofl_queue_stats **dst) { struct ofl_queue_stats *p; if (*len < sizeof(struct ofp_queue_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received queue stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (ntohl(src->port_no) == 0 || ntohl(src->port_no) > OFPP_MAX) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(src->port_no)); OFL_LOG_WARN(LOG_MODULE, "Received queue stats has invalid port_id (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_queue_stats); p = (struct ofl_queue_stats *)malloc(sizeof(struct ofl_queue_stats)); p->port_no = ntohl(src->port_no); p->queue_id = ntohl(src->queue_id); p->tx_bytes = ntoh64(src->tx_bytes); p->tx_packets = ntoh64(src->tx_packets); p->tx_errors = ntoh64(src->tx_errors); p->duration_sec = ntohl(src->duration_sec); p->duration_nsec = ntohl(src->duration_nsec); *dst = p; return 0; }
ofl_err ofl_structs_table_stats_unpack(struct ofp_table_stats *src, size_t *len, struct ofl_table_stats **dst) { struct ofl_table_stats *p; if (*len < sizeof(struct ofp_table_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } if (src->table_id == 0xff) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ts = ofl_table_to_string(src->table_id); OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid table_id (%s).", ts); free(ts); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_table_stats); p = (struct ofl_table_stats *)malloc(sizeof(struct ofl_table_stats)); p->table_id = src->table_id; p->active_count = ntohl(src->active_count); p->lookup_count = ntoh64(src->lookup_count); p->matched_count = ntoh64(src->matched_count); *dst = p; return 0; }
static ofl_err ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { struct ofp_port_mod *sm; struct ofl_msg_port_mod *dm; if (*len < sizeof(struct ofp_port_mod)) { OFL_LOG_WARN(LOG_MODULE, "Received PORT_MOD has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } sm = (struct ofp_port_mod *)src; if (ntohl(sm->port_no) == 0 || ntohl(sm->port_no) > OFPP_MAX) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(sm->port_no)); OFL_LOG_WARN(LOG_MODULE, "Received PORT_MOD message has invalid in_port (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } *len -= sizeof(struct ofp_port_mod); dm = (struct ofl_msg_port_mod *)malloc(sizeof(struct ofl_msg_port_mod)); dm->port_no = ntohl(sm->port_no); memcpy(dm->hw_addr, sm->hw_addr, OFP_ETH_ALEN); dm->config = ntohl(sm->config); dm->mask = ntohl(sm->mask); dm->advertise = ntohl(sm->advertise); *msg = (struct ofl_msg_header *)dm; return 0; }
static ofl_err ofl_msg_unpack_flow_removed(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { struct ofp_flow_removed *sr; struct ofl_msg_flow_removed *dr; ofl_err error; if (*len < (sizeof(struct ofp_flow_removed) - sizeof(struct ofp_match))) { OFL_LOG_WARN(LOG_MODULE, "Received FLOW_REMOVED message has invalid length (%zu).", *len); return OFL_ERROR; } sr = (struct ofp_flow_removed *)src; if (sr->table_id == 0xff) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ts = ofl_table_to_string(sr->table_id); OFL_LOG_WARN(LOG_MODULE, "Received FLOW_REMOVED message has invalid table_id (%s).", ts); free(ts); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } *len -= (sizeof(struct ofp_flow_removed) - sizeof(struct ofp_match)); dr = (struct ofl_msg_flow_removed *)malloc(sizeof(struct ofl_msg_flow_removed)); dr->reason = (enum ofp_flow_removed_reason)sr->reason; dr->stats = (struct ofl_flow_stats *)malloc(sizeof(struct ofl_flow_stats)); dr->stats->table_id = sr->table_id; dr->stats->duration_sec = ntohl( sr->duration_sec); dr->stats->duration_nsec = ntohl( sr->duration_nsec); dr->stats->priority = ntoh64(sr->priority); dr->stats->idle_timeout = ntohs( sr->idle_timeout); dr->stats->hard_timeout = 0; dr->stats->cookie = ntoh64(sr->cookie); dr->stats->packet_count = ntoh64(sr->packet_count); dr->stats->byte_count = ntoh64(sr->byte_count); dr->stats->instructions_num = 0; dr->stats->instructions = NULL; error = ofl_structs_match_unpack(&(sr->match), len, &(dr->stats->match), exp); if (error) { free(dr->stats); free(dr); return error; } *msg = (struct ofl_msg_header *)dr; return 0; }
ofl_err ofl_structs_port_stats_unpack(struct ofp_port_stats *src, size_t *len, struct ofl_port_stats **dst) { struct ofl_port_stats *p; if (*len < sizeof(struct ofp_port_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received port stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } if (ntohl(src->port_no) == 0 || (ntohl(src->port_no) > OFPP_MAX && ntohl(src->port_no) != OFPP_LOCAL)) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(src->port_no)); OFL_LOG_WARN(LOG_MODULE, "Received port stats has invalid port_id (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_port_stats); p = (struct ofl_port_stats *)malloc(sizeof(struct ofl_port_stats)); p->port_no = ntohl(src->port_no); p->rx_packets = ntoh64(src->rx_packets); p->tx_packets = ntoh64(src->tx_packets); p->rx_bytes = ntoh64(src->rx_bytes); p->tx_bytes = ntoh64(src->tx_bytes); p->rx_dropped = ntoh64(src->rx_dropped); p->tx_dropped = ntoh64(src->tx_dropped); p->rx_errors = ntoh64(src->rx_errors); p->tx_errors = ntoh64(src->tx_errors); p->rx_frame_err = ntoh64(src->rx_frame_err); p->rx_over_err = ntoh64(src->rx_over_err); p->rx_crc_err = ntoh64(src->rx_crc_err); p->collisions = ntoh64(src->collisions); p->duration_sec = ntohl(src->duration_sec); p->duration_nsec = ntohl(src->duration_nsec); *dst = p; return 0; }
ofl_err ofl_structs_port_unpack(struct ofp_port *src, size_t *len, struct ofl_port **dst) { struct ofl_port *p; if (*len < sizeof(struct ofp_port)) { OFL_LOG_WARN(LOG_MODULE, "Received port has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } if (ntohl(src->port_no) == 0 || (ntohl(src->port_no) > OFPP_MAX && ntohl(src->port_no) != OFPP_LOCAL)) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(src->port_no)); OFL_LOG_WARN(LOG_MODULE, "Received port has invalid port_id (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_port); p = (struct ofl_port *)malloc(sizeof(struct ofl_port)); p->port_no = ntohl(src->port_no); memcpy(p->hw_addr, src->hw_addr, ETH_ADDR_LEN); p->name = strcpy((char *)malloc(strlen(src->name) + 1), src->name); p->config = ntohl(src->config); p->state = ntohl(src->state); p->curr = ntohl(src->curr); p->advertised = ntohl(src->advertised); p->supported = ntohl(src->supported); p->peer = ntohl(src->peer); p->curr_speed = ntohl(src->curr_speed); p->max_speed = ntohl(src->max_speed); *dst = p; return 0; }
ofl_err ofl_structs_table_stats_unpack(struct ofp_table_stats *src, size_t *len, struct ofl_table_stats **dst) { struct ofl_table_stats *p; if (*len < sizeof(struct ofp_table_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } if (src->table_id == 0xff) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ts = ofl_table_to_string(src->table_id); OFL_LOG_WARN(LOG_MODULE, "Received table stats has invalid table_id (%s).", ts); free(ts); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_table_stats); p = (struct ofl_table_stats *)malloc(sizeof(struct ofl_table_stats)); p->table_id = src->table_id; p->name = strcpy((char *)malloc(strlen(src->name) + 1), src->name); p->wildcards = ntohl(src->wildcards); p->match = ntohl(src->match); p->instructions = ntohl(src->instructions); p->write_actions = ntohl(src->write_actions); p->apply_actions = ntohl(src->apply_actions); p->config = ntohl(src->config); p->max_entries = ntohl(src->max_entries); p->active_count = ntohl(src->active_count); p->lookup_count = ntoh64(src->lookup_count); p->matched_count = ntoh64(src->matched_count); *dst = p; return 0; }
ofl_err ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct ofl_instruction_header **dst, struct ofl_exp *exp) { size_t ilen; struct ofl_instruction_header *inst = NULL; if (*len < sizeof(struct ofp_instruction)) { OFL_LOG_WARN(LOG_MODULE, "Received instruction 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 instruction has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } ilen = ntohs(src->len); switch (ntohs(src->type)) { case OFPIT_GOTO_TABLE: { struct ofp_instruction_goto_table *si; struct ofl_instruction_goto_table *di; if (ilen < sizeof(struct ofp_instruction_goto_table)) { OFL_LOG_WARN(LOG_MODULE, "Received GOTO_TABLE instruction has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } si = (struct ofp_instruction_goto_table *)src; if (si->table_id >= PIPELINE_TABLES) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ts = ofl_table_to_string(si->table_id); OFL_LOG_WARN(LOG_MODULE, "Received GOTO_TABLE instruction has invalid table_id (%s).", ts); free(ts); } return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_BAD_TABLE_ID); } di = (struct ofl_instruction_goto_table *)malloc(sizeof(struct ofl_instruction_goto_table)); di->table_id = si->table_id; inst = (struct ofl_instruction_header *)di; ilen -= sizeof(struct ofp_instruction_goto_table); break; } case OFPIT_WRITE_METADATA: { struct ofp_instruction_write_metadata *si; struct ofl_instruction_write_metadata *di; if (ilen < sizeof(struct ofp_instruction_write_metadata)) { OFL_LOG_WARN(LOG_MODULE, "Received WRITE_METADATA instruction has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } si = (struct ofp_instruction_write_metadata *)src; di = (struct ofl_instruction_write_metadata *)malloc(sizeof(struct ofl_instruction_write_metadata)); di->metadata = ntoh64(si->metadata); di->metadata_mask = ntoh64(si->metadata_mask); inst = (struct ofl_instruction_header *)di; ilen -= sizeof(struct ofp_instruction_write_metadata); break; } case OFPIT_WRITE_ACTIONS: case OFPIT_APPLY_ACTIONS: { struct ofp_instruction_actions *si; struct ofl_instruction_actions *di; struct ofp_action_header *act; ofl_err error; size_t i; if (ilen < sizeof(struct ofp_instruction_actions)) { OFL_LOG_WARN(LOG_MODULE, "Received *_ACTIONS instruction has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } ilen -= sizeof(struct ofp_instruction_actions); si = (struct ofp_instruction_actions *)src; di = (struct ofl_instruction_actions *)malloc(sizeof(struct ofl_instruction_actions)); error = ofl_utils_count_ofp_actions((uint8_t *)si->actions, ilen, &di->actions_num); if (error) { free(di); return error; } di->actions = (struct ofl_action_header **)malloc(di->actions_num * sizeof(struct ofl_action_header *)); act = si->actions; for (i = 0; i < di->actions_num; i++) { error = ofl_actions_unpack(act, &ilen, &(di->actions[i]), exp); if (error) { *len = *len - ntohs(src->len) + ilen; OFL_UTILS_FREE_ARR_FUN2(di->actions, i, ofl_actions_free, exp); free(di); return error; } act = (struct ofp_action_header *)((uint8_t *)act + ntohs(act->len)); } inst = (struct ofl_instruction_header *)di; break; } case OFPIT_CLEAR_ACTIONS: { if (ilen < sizeof(struct ofp_instruction_actions)) { OFL_LOG_WARN(LOG_MODULE, "Received CLEAR_ACTIONS instruction has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } inst = (struct ofl_instruction_header *)malloc(sizeof(struct ofl_instruction_header)); inst->type = (enum ofp_instruction_type)ntohs(src->type); ilen -= sizeof(struct ofp_instruction_actions); break; } case OFPIT_METER: { struct ofp_instruction_meter *si; struct ofl_instruction_meter *di; if (ilen < sizeof(struct ofp_instruction_meter)) { OFL_LOG_WARN(LOG_MODULE, "Received METER instruction has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } si = (struct ofp_instruction_meter*)src; di = (struct ofl_instruction_meter *)malloc(sizeof(struct ofl_instruction_meter)); di->meter_id = ntohl(si->meter_id); inst = (struct ofl_instruction_header *)di; ilen -= sizeof(struct ofp_instruction_meter); break; } case OFPIT_EXPERIMENTER: { ofl_err error; if (exp == NULL || exp->inst == NULL || exp->inst->unpack == NULL) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER instruction, but no callback was given."); return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); } error = exp->inst->unpack(src, &ilen, &inst); if (error) { return error; } break; } default: OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%u) is invalid.", ntohs(src->type)); return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNKNOWN_INST); } // must set type before check, so free works correctly inst->type = (enum ofp_instruction_type)ntohs(src->type); if (ilen != 0) { *len = *len - ntohs(src->len) + ilen; OFL_LOG_WARN(LOG_MODULE, "The received instruction contained extra bytes (%zu).", ilen); ofl_structs_free_instruction(inst, exp); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->len); (*dst) = inst; return 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; 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; }
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_SET_VLAN_VID: { struct ofp_action_vlan_vid *sa; struct ofl_action_vlan_vid *da; if (*len < sizeof(struct ofp_action_vlan_vid)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_VID action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_vlan_vid *)src; if (ntohs(sa->vlan_vid) > VLAN_VID_MAX) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *vs = ofl_vlan_vid_to_string(ntohs(sa->vlan_vid)); OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_VID action has invalid vid (%s).", vs); free(vs); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_vlan_vid *)malloc(sizeof(struct ofl_action_vlan_vid)); da->vlan_vid = ntohs(sa->vlan_vid); *len -= sizeof(struct ofp_action_vlan_vid); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_VLAN_PCP: { struct ofp_action_vlan_pcp *sa; struct ofl_action_vlan_pcp *da; if (*len < sizeof(struct ofp_action_vlan_pcp)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_PCP action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_vlan_pcp *)src; if (sa->vlan_pcp > VLAN_PCP_MAX) { OFL_LOG_WARN(LOG_MODULE, "Received SET_VLAN_PCP action has invalid pcp (%u).", sa->vlan_pcp); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_vlan_pcp *)malloc(sizeof(struct ofl_action_vlan_pcp)); da->vlan_pcp = sa->vlan_pcp; *len -= sizeof(struct ofp_action_vlan_pcp); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_DL_SRC: case OFPAT_SET_DL_DST: { struct ofp_action_dl_addr *sa; struct ofl_action_dl_addr *da; if (*len < sizeof(struct ofp_action_dl_addr)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_DL_SRC/DST action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_dl_addr *)src; da = (struct ofl_action_dl_addr *)malloc(sizeof(struct ofl_action_dl_addr)); memcpy(&(da->dl_addr), &(sa->dl_addr), OFP_ETH_ALEN); *len -= sizeof(struct ofp_action_dl_addr); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_NW_SRC: case OFPAT_SET_NW_DST: { struct ofp_action_nw_addr *sa; struct ofl_action_nw_addr *da; if (*len < sizeof(struct ofp_action_nw_addr)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_SRC/DST action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_nw_addr *)src; da = (struct ofl_action_nw_addr *)malloc(sizeof(struct ofl_action_nw_addr)); da->nw_addr = sa->nw_addr; *len -= sizeof(struct ofp_action_nw_addr); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_NW_TOS: { struct ofp_action_nw_tos *sa; struct ofl_action_nw_tos *da; if (*len < sizeof(struct ofp_action_nw_tos)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TOS action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_nw_tos *)src; if (sa->nw_tos > IP_DSCP_MASK) { OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_TOS action has invalid tos value (%u).", sa->nw_tos); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_nw_tos *)malloc(sizeof(struct ofl_action_nw_tos)); da->nw_tos = sa->nw_tos; *len -= sizeof(struct ofp_action_nw_tos); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_NW_ECN: { struct ofp_action_nw_ecn *sa; struct ofl_action_nw_ecn *da; if (*len < sizeof(struct ofp_action_nw_ecn)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_ECN action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_nw_ecn *)src; if (sa->nw_ecn > IP_ECN_MASK) { OFL_LOG_WARN(LOG_MODULE, "Received SET_NW_ECN action has invalid ecn value (%u).", sa->nw_ecn); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_nw_ecn *)malloc(sizeof(struct ofl_action_nw_ecn)); da->nw_ecn = sa->nw_ecn; *len -= sizeof(struct ofp_action_nw_ecn); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_TP_SRC: case OFPAT_SET_TP_DST: { struct ofp_action_tp_port *sa; struct ofl_action_tp_port *da; if (*len < sizeof(struct ofp_action_tp_port)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_TP_SRC/DST action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_tp_port *)src; da = (struct ofl_action_tp_port *)malloc(sizeof(struct ofl_action_tp_port)); da->tp_port = ntohs(sa->tp_port); *len -= sizeof(struct ofp_action_tp_port); *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_LABEL: { struct ofp_action_mpls_label *sa; struct ofl_action_mpls_label *da; if (*len < sizeof(struct ofp_action_mpls_label)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_LABEL action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_mpls_label *)src; if (ntohl(sa->mpls_label) > MPLS_LABEL_MAX) { OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_LABEL action has invalid label value (%u).", ntohl(sa->mpls_label)); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_mpls_label *)malloc(sizeof(struct ofl_action_mpls_label)); da->mpls_label = ntohl(sa->mpls_label); *len -= sizeof(struct ofp_action_mpls_label); *dst = (struct ofl_action_header *)da; break; } case OFPAT_SET_MPLS_TC: { struct ofp_action_mpls_tc *sa; struct ofl_action_mpls_tc *da; if (*len < sizeof(struct ofp_action_mpls_tc)) { OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TC action has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } sa = (struct ofp_action_mpls_tc *)src; if (sa->mpls_tc > MPLS_TC_MAX) { OFL_LOG_WARN(LOG_MODULE, "Received SET_MPLS_TC action has invalid tc value (%u).", sa->mpls_tc); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } da = (struct ofl_action_mpls_tc *)malloc(sizeof(struct ofl_action_mpls_tc)); da->mpls_tc = sa->mpls_tc; *len -= sizeof(struct ofp_action_mpls_tc); *dst = (struct ofl_action_header *)da; 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_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 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))) { OFL_LOG_WARN(LOG_MODULE, "Received PUSH_VLAN/MPLS 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: { //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_ARGUMENT); } 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 = ntohs(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_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; }
ofl_err ofl_structs_group_stats_unpack(struct ofp_group_stats *src, size_t *len, struct ofl_group_stats **dst) { struct ofl_group_stats *s; struct ofp_bucket_counter *c; ofl_err error; size_t slen; size_t i; if (*len < sizeof(struct ofp_group_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received group desc stats reply is too short (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received group stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (ntohl(src->group_id) > OFPG_MAX) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *gs = ofl_group_to_string(ntohl(src->group_id)); OFL_LOG_WARN(LOG_MODULE, "Received group stats has invalid group_id (%s).", gs); free(gs); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } slen = ntohs(src->length) - sizeof(struct ofp_group_stats); s = (struct ofl_group_stats *)malloc(sizeof(struct ofl_group_stats)); s->group_id = ntohl(src->group_id); s->ref_count = ntohl(src->ref_count); s->packet_count = ntoh64(src->packet_count); s->byte_count = ntoh64(src->byte_count); s->duration_sec = htonl(src->duration_sec); s->duration_nsec = htonl(src->duration_nsec); error = ofl_utils_count_ofp_bucket_counters(src->bucket_stats, slen, &s->counters_num); if (error) { free(s); return error; } s->counters = (struct ofl_bucket_counter **)malloc(s->counters_num * sizeof(struct ofl_bucket_counter *)); c = src->bucket_stats; for (i = 0; i < s->counters_num; i++) { error = ofl_structs_bucket_counter_unpack(c, &slen, &(s->counters[i])); if (error) { OFL_UTILS_FREE_ARR(s->counters, i); free(s); return error; } c = (struct ofp_bucket_counter *)((uint8_t *)c + sizeof(struct ofp_bucket_counter)); } if (slen != 0) { *len = *len - ntohs(src->length) + slen; OFL_LOG_WARN(LOG_MODULE, "The received group stats contained extra bytes (%zu).", slen); ofl_structs_free_group_stats(s); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->length); *dst = s; return 0; }
ofl_err ofl_structs_flow_stats_unpack(struct ofp_flow_stats *src, uint8_t *buf, size_t *len, struct ofl_flow_stats **dst, struct ofl_exp *exp) { struct ofl_flow_stats *s; struct ofp_instruction *inst; ofl_err error; size_t slen; size_t i; int match_pos; if (*len < ( (sizeof(struct ofp_flow_stats) - sizeof(struct ofp_match)) + ROUND_UP(ntohs(src->match.length),8))) { OFL_LOG_WARN(LOG_MODULE, "Received flow stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received flow stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (src->table_id >= PIPELINE_TABLES) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ts = ofl_table_to_string(src->table_id); OFL_LOG_WARN(LOG_MODULE, "Received flow stats has invalid table_id (%s).", ts); free(ts); } return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } slen = ntohs(src->length) - (sizeof(struct ofp_flow_stats) - sizeof(struct ofp_match)); s = (struct ofl_flow_stats *)malloc(sizeof(struct ofl_flow_stats)); s->table_id = src->table_id; s->duration_sec = ntohl( src->duration_sec); s->duration_nsec = ntohl( src->duration_nsec); s->priority = ntohs( src->priority); s->idle_timeout = ntohs( src->idle_timeout); s->hard_timeout = ntohs( src->hard_timeout); s->cookie = ntoh64(src->cookie); s->packet_count = ntoh64(src->packet_count); s->byte_count = ntoh64(src->byte_count); match_pos = sizeof(struct ofp_flow_stats) - 4; error = ofl_structs_match_unpack(&(src->match),buf + match_pos , &slen, &(s->match), exp); if (error) { free(s); return error; } error = ofl_utils_count_ofp_instructions((struct ofp_instruction *) (buf + ROUND_UP(match_pos + s->match->length,8)), slen, &s->instructions_num); if (error) { ofl_structs_free_match(s->match, exp); free(s); return error; } s->instructions = (struct ofl_instruction_header **)malloc(s->instructions_num * sizeof(struct ofl_instruction_header *)); inst = (struct ofp_instruction *) (buf + ROUND_UP(match_pos + s->match->length,8)); for (i = 0; i < s->instructions_num; i++) { error = ofl_structs_instructions_unpack(inst, &slen, &(s->instructions[i]), exp); if (error) { OFL_UTILS_FREE_ARR_FUN2(s->instructions, i, ofl_structs_free_instruction, exp); free(s); return error; } inst = (struct ofp_instruction *)((uint8_t *)inst + ntohs(inst->len)); } if (slen != 0) { *len = *len - ntohs(src->length) + slen; OFL_LOG_WARN(LOG_MODULE, "The received flow stats contained extra bytes (%zu).", slen); ofl_structs_free_flow_stats(s, exp); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->length); *dst = s; return 0; }
ofl_err ofl_structs_group_desc_stats_unpack(struct ofp_group_desc_stats *src, size_t *len, struct ofl_group_desc_stats **dst, struct ofl_exp *exp) { struct ofl_group_desc_stats *dm; struct ofp_bucket *bucket; ofl_err error; size_t dlen; size_t i; if (*len < sizeof(struct ofp_group_desc_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received group desc stats reply is too short (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received group desc stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (ntohl(src->group_id) > OFPG_MAX) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *gs = ofl_group_to_string(ntohl(src->group_id)); OFL_LOG_WARN(LOG_MODULE, "Received group desc stats has invalid group_id (%s).", gs); free(gs); } return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } dlen = ntohs(src->length) - sizeof(struct ofp_group_desc_stats); dm = (struct ofl_group_desc_stats *)malloc(sizeof(struct ofl_group_desc_stats)); dm->type = src->type; dm->group_id = ntohl(src->group_id); error = ofl_utils_count_ofp_buckets(src->buckets, dlen, &dm->buckets_num); if (error) { free(dm); return error; } dm->buckets = (struct ofl_bucket **)malloc(dm->buckets_num * sizeof(struct ofl_bucket *)); bucket = src->buckets; for (i = 0; i < dm->buckets_num; i++) { error = ofl_structs_bucket_unpack(bucket, &dlen, dm->type, &(dm->buckets[i]), exp); if (error) { OFL_UTILS_FREE_ARR_FUN2(dm->buckets, i, ofl_structs_free_bucket, exp); free (dm); return error; } bucket = (struct ofp_bucket *)((uint8_t *)bucket + ntohs(bucket->len)); } if (dlen != 0) { *len = *len - ntohs(src->length) + dlen; OFL_LOG_WARN(LOG_MODULE, "The received group desc stats contained extra bytes (%zu).", dlen); ofl_structs_free_group_desc_stats(dm, exp); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->length); *dst = dm; return 0; }
static ofl_err ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { struct ofp_group_mod *sm; struct ofl_msg_group_mod *dm; struct ofp_bucket *bucket; ofl_err error; size_t i; if (*len < sizeof(struct ofp_group_mod)) { OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_group_mod); sm = (struct ofp_group_mod *)src; if (ntohs(sm->command) > OFPGC_DELETE) { OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message with invalid command (%u).", ntohs(sm->command)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); } if (ntohs(sm->type) > OFPGT_FF && ntohs(sm->type) < 128 /* experimenter */) { OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message with invalid type (%u).", ntohs(sm->type)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); } if (ntohl(sm->group_id) > OFPG_MAX && !(ntohs(sm->command) == OFPGC_DELETE && ntohl(sm->group_id) == OFPG_ALL)) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *gs = ofl_group_to_string(ntohl(sm->group_id)); OFL_LOG_WARN(LOG_MODULE, "Received GROUP_MOD message with invalid group id (%s).", gs); free(gs); } return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP); } dm = (struct ofl_msg_group_mod *)malloc(sizeof(struct ofl_msg_group_mod)); dm->command = (enum ofp_group_mod_command)ntohs(sm->command); dm->type = sm->type; dm->group_id = ntohl(sm->group_id); error = ofl_utils_count_ofp_buckets(&(sm->buckets), *len, &dm->buckets_num); if (error) { free(dm); return error; } if (dm->command == OFPGC_DELETE && dm->buckets_num > 0) { OFL_LOG_WARN(LOG_MODULE, "Received DELETE group command with buckets (%zu).", dm->buckets_num); free(dm); return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP); } if (dm->type == OFPGT_INDIRECT && dm->buckets_num != 1) { OFL_LOG_WARN(LOG_MODULE, "Received INDIRECT group doesn't have exactly one bucket (%zu).", dm->buckets_num); free(dm); return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_INVALID_GROUP); } dm->buckets = (struct ofl_bucket **)malloc(dm->buckets_num * sizeof(struct ofl_bucket *)); bucket = sm->buckets; for (i = 0; i < dm->buckets_num; i++) { error = ofl_structs_bucket_unpack(bucket, len, dm->type, &(dm->buckets[i]), exp); if (error) { OFL_UTILS_FREE_ARR_FUN2(dm->buckets, i, ofl_structs_free_bucket, exp); free(dm); return error; } bucket = (struct ofp_bucket *)((uint8_t *)bucket + ntohs(bucket->len)); } *msg = (struct ofl_msg_header *)dm; return 0; }
static ofl_err ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { struct ofp_packet_out *sp; struct ofl_msg_packet_out *dp; struct ofp_action_header *act; uint8_t *data; ofl_err error; size_t i, actions_num; if (*len < sizeof(struct ofp_packet_out)) { OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } sp = (struct ofp_packet_out *)src; if (ntohl(sp->in_port) == 0 || (ntohl(sp->in_port) > OFPP_MAX && ntohl(sp->in_port) != OFPP_CONTROLLER)) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *ps = ofl_port_to_string(ntohl(sp->in_port)); OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message with invalid in_port (%s).", ps); free(ps); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT); } if (ntohl(sp->buffer_id) != 0xffffffff && *len != sizeof(struct ofp_packet_out) + ntohs(sp->actions_len)) { if (OFL_LOG_IS_WARN_ENABLED(LOG_MODULE)) { char *bs = ofl_buffer_to_string(ntohl(sp->buffer_id)); OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message with data and buffer_id (%s).", bs); free(bs); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_packet_out); dp = (struct ofl_msg_packet_out *)malloc(sizeof(struct ofl_msg_packet_out)); dp->buffer_id = ntohl(sp->buffer_id); dp->in_port = ntohl(sp->in_port); if (*len < ntohs(sp->actions_len)) { OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message has invalid action length (%zu).", *len); free(dp); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } error = ofl_utils_count_ofp_actions(&(sp->actions), ntohs(sp->actions_len), &actions_num); if (error) { free(dp); return error; } dp->actions_num = actions_num; dp->actions = (struct ofl_action_header **)malloc(dp->actions_num * sizeof(struct ofp_action_header *)); // TODO Zoltan: Output actions can contain OFPP_TABLE act = sp->actions; for (i = 0; i < dp->actions_num; i++) { error = ofl_actions_unpack(act, len, &(dp->actions[i]), exp); if (error) { OFL_UTILS_FREE_ARR_FUN2(dp->actions, i, ofl_actions_free, exp); free(dp); } act = (struct ofp_action_header *)((uint8_t *)act + ntohs(act->len)); } data = ((uint8_t *)sp->actions) + ntohs(sp->actions_len); dp->data_length = *len; dp->data = *len > 0 ? (uint8_t *)memcpy(malloc(*len), data, *len) : NULL; *len = 0; *msg = (struct ofl_msg_header *)dp; return 0; }