/* ADD_MESSAGE message operation. */ static ofl_err bundle_add_msg(struct bundle_table *table, struct ofl_msg_bundle_add_msg *add_msg) { struct bundle_table_entry *entry; struct bundle_message *new_message; ofl_err error = 0; entry = bundle_table_entry_find(table, add_msg->bundle_id); if (entry != NULL) { if (entry->flags != add_msg->flags) { error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BAD_FLAGS); bundle_table_entry_destroy(entry); } else if (entry->closed) { error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BUNDLE_CLOSED); bundle_table_entry_destroy(entry); } } else { entry = bundle_table_entry_create(add_msg->bundle_id, add_msg->flags); list_push_back(&table->bundle_table_entries, &entry->node); } if (!error) { new_message = bundle_message_create(add_msg); list_push_back(&entry->bundle_message_list, &new_message->node); } return error; }
/* Close operation. */ static ofl_err bundle_close(struct bundle_table *table, uint32_t bundle_id, uint16_t flags) { struct bundle_table_entry *entry; ofl_err error; entry = bundle_table_entry_find(table, bundle_id); if (entry == NULL) { error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BAD_ID); } else { if (entry->flags != flags) { error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BAD_FLAGS); bundle_table_entry_destroy(entry); } else if (entry->closed) { error = ofl_error(OFPET_BUNDLE_FAILED, OFPBFC_BUNDLE_CLOSED); bundle_table_entry_destroy(entry); } else { /* TODO check bundled messages (e.g. syntax / parameter check * and perform dry run of execution) to gain more confidence * that commit will succeed, return error if any issues found */ /* Mark closed */ entry->closed = true; error = 0; } } return error; }
/* Handles group_mod messages with MODIFY command. */ static ofl_err group_table_modify(struct group_table *table, struct ofl_msg_group_mod *mod) { struct group_entry *entry, *new_entry; entry = group_table_find(table, mod->group_id); if (entry == NULL) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_UNKNOWN_GROUP); } if (table->buckets_num - entry->desc->buckets_num + mod->buckets_num > GROUP_TABLE_MAX_BUCKETS) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_OUT_OF_BUCKETS); } if (!is_loop_free(table, entry)) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_LOOP); } new_entry = group_entry_create(table->dp, table, mod); hmap_remove(&table->entries, &entry->node); hmap_insert_fast(&table->entries, &new_entry->node, mod->group_id); table->buckets_num = table->buckets_num - entry->desc->buckets_num + new_entry->desc->buckets_num; group_entry_destroy(entry); ofl_msg_free_group_mod(mod, false, table->dp->exp); return 0; }
ofl_err ofl_exp_msg_unpack(struct ofp_header const *oh, size_t *len, struct ofl_msg_experimenter **msg, struct ofl_exp const * ofl_exp) { struct ofp_experimenter_header *exp; if (*len < sizeof(struct ofp_experimenter_header)) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER message is shorter than ofp_experimenter_header."); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } exp = (struct ofp_experimenter_header *)oh; switch (ntohl(exp->experimenter)) { case (OPENFLOW_VENDOR_ID): { return ofl_exp_openflow_msg_unpack(oh, len, msg); } case (NX_VENDOR_ID): { return ofl_exp_nicira_msg_unpack(oh, len, msg); } case (BEBA_VENDOR_ID): { return ofl_exp_beba_msg_unpack(oh, len, msg, ofl_exp); } default: { OFL_LOG_WARN(LOG_MODULE, "Trying to unpack unknown EXPERIMENTER message (%u).", ntohl(exp->experimenter)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_EXPERIMENTER); } } }
static ofl_err ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, char *errbuf) { struct ofp_port_mod *sm; struct ofl_msg_port_mod *dm; if (*len < sizeof(struct ofp_port_mod)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *ps = ofl_port_to_string(ntohl(sm->port_no)); snprintf(errbuf, OFL_ERRBUF_SIZE, "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; }
ofl_err ofl_structs_queue_stats_unpack(struct ofp_queue_stats *src, size_t *len, struct ofl_queue_stats **dst, char *errbuf) { struct ofl_queue_stats *p; if (*len < sizeof(struct ofp_queue_stats)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *ps = ofl_port_to_string(ntohl(src->port_no)); snprintf(errbuf, OFL_ERRBUF_SIZE, "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); *dst = p; return 0; }
static ofl_err ofl_msg_unpack_stats_request_queue(struct ofp_stats_request *os, size_t *len, struct ofl_msg_header **msg, char *errbuf) { struct ofp_queue_stats_request *sm; struct ofl_msg_stats_request_queue *dm; // ofp_stats_request length was checked at ofl_msg_unpack_stats_request if (*len < sizeof(struct ofp_queue_stats_request)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received QUEUE stats request has invalid length (%zu).", *len); } return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } sm = (struct ofp_queue_stats_request *)os->body; if (ntohl(sm->port_no) == 0 || (ntohl(sm->port_no) > OFPP_MAX && ntohl(sm->port_no) != OFPP_ANY)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received QUEUE stats request has invalid port (%u).", ntohl(sm->port_no)); } return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_queue_stats_request); dm = (struct ofl_msg_stats_request_queue *)malloc(sizeof(struct ofl_msg_stats_request_queue)); dm->port_no = ntohl(sm->port_no); dm->queue_id = ntohl(sm->queue_id); *msg = (struct ofl_msg_header *)dm; 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; }
/* Handles meter_mod messages with ADD command. */ static ofl_err meter_table_add(struct meter_table *table, struct ofl_msg_meter_mod *mod) { struct meter_entry *entry; if (hmap_first_with_hash(&table->meter_entries, mod->meter_id) != NULL) { return ofl_error(OFPET_METER_MOD_FAILED, OFPMMFC_METER_EXISTS); } if (table->entries_num == DEFAULT_MAX_METER) { return ofl_error(OFPET_METER_MOD_FAILED, OFPMMFC_OUT_OF_METERS); } if (table->bands_num + mod->meter_bands_num > METER_TABLE_MAX_BANDS) { return ofl_error(OFPET_METER_MOD_FAILED, OFPMMFC_OUT_OF_BANDS); } entry = meter_entry_create(table->dp, table, mod); hmap_insert(&table->meter_entries, &entry->node, entry->stats->meter_id); table->entries_num++; table->bands_num += entry->stats->meter_bands_num; ofl_msg_free_meter_mod(mod, false); return 0; }
/* Handles meter_mod messages with MODIFY command. */ static ofl_err meter_table_modify(struct meter_table *table, struct ofl_msg_meter_mod *mod) { struct meter_entry *entry, *new_entry; entry = meter_table_find(table, mod->meter_id); if (entry == NULL) { return ofl_error(OFPET_METER_MOD_FAILED, OFPMMFC_UNKNOWN_METER); } if (table->bands_num - entry->config->meter_bands_num + mod->meter_bands_num > METER_TABLE_MAX_BANDS) { return ofl_error(OFPET_METER_MOD_FAILED, OFPMMFC_OUT_OF_BANDS); } new_entry = meter_entry_create(table->dp, table, mod); hmap_remove(&table->meter_entries, &entry->node); hmap_insert_fast(&table->meter_entries, &new_entry->node, mod->meter_id); table->bands_num = table->bands_num - entry->config->meter_bands_num + new_entry->stats->meter_bands_num; /* keep flow references from old meter entry */ list_replace(&new_entry->flow_refs, &entry->flow_refs); list_init(&entry->flow_refs); meter_entry_destroy(entry); ofl_msg_free_meter_mod(mod, false); return 0; }
static ofl_err ofl_msg_unpack_stats_request_port(struct ofp_stats_request *os, size_t *len, struct ofl_msg_header **msg) { struct ofp_port_stats_request *sm; struct ofl_msg_stats_request_port *dm; // ofp_stats_request length was checked at ofl_msg_unpack_stats_request if (*len < sizeof(struct ofp_port_stats_request)) { OFL_LOG_WARN(LOG_MODULE, "Received PORT stats request has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } sm = (struct ofp_port_stats_request *)os->body; if (ntohl(sm->port_no) == 0 || (ntohl(sm->port_no) > OFPP_MAX && ntohl(sm->port_no) != OFPP_ANY)) { OFL_LOG_WARN(LOG_MODULE, "Received PORT stats request has invalid port (%u).", ntohl(sm->port_no)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_port_stats_request); dm = (struct ofl_msg_stats_request_port *)malloc(sizeof(struct ofl_msg_stats_request_port)); dm->port_no = ntohl(sm->port_no); *msg = (struct ofl_msg_header *)dm; return 0; }
/* Handles group mod messages with ADD command. */ static ofl_err group_table_add(struct group_table *table, struct ofl_msg_group_mod *mod) { struct group_entry *entry; if (hmap_first_with_hash(&table->entries, mod->group_id) != NULL) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_GROUP_EXISTS); } if (table->entries_num == GROUP_TABLE_MAX_ENTRIES) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_OUT_OF_GROUPS); } if (table->buckets_num + mod->buckets_num > GROUP_TABLE_MAX_BUCKETS) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_OUT_OF_BUCKETS); } entry = group_entry_create(table->dp, table, mod); hmap_insert(&table->entries, &entry->node, entry->stats->group_id); table->entries_num++; table->buckets_num += entry->desc->buckets_num; ofl_msg_free_group_mod(mod, false, table->dp->exp); return 0; }
ofl_err ofl_exp_msg_unpack(struct ofp_header *oh, size_t *len, struct ofl_msg_experimenter **msg) { struct ofp_experimenter_header *exp; if (*len < sizeof(struct ofp_experimenter_header)) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER message is shorter than ofp_experimenter_header."); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } exp = (struct ofp_experimenter_header *)oh; switch (htonl(exp->experimenter)) { case (OPENFLOW_VENDOR_ID): { return ofl_exp_openflow_msg_unpack(oh, len, msg); } /* Acrescentado pelo FRESDWN case (NX_VENDOR_ID): { return ofl_exp_nicira_msg_unpack(oh, len, msg); } */ case (NX_VENDOR_ID): { return ofl_exp_nicira_msg_unpack(oh, len, msg); } case (FRESDWN_VENDOR_ID): { return ofl_exp_fresdwn_msg_unpack(oh, len, msg); } default: { OFL_LOG_WARN(LOG_MODULE, "Trying to unpack unknown EXPERIMENTER message (%u).", htonl(exp->experimenter)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_EXPERIMENTER); } } }
ofl_err ofl_structs_meter_stats_unpack(struct ofp_meter_stats *src, size_t *len, struct ofl_meter_stats **dst) { struct ofl_meter_stats *s; struct ofp_meter_band_stats *c; ofl_err error; size_t slen; size_t i; if (*len < sizeof(struct ofp_meter_stats)) { OFL_LOG_WARN(LOG_MODULE, "Received meter stats reply is too short (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received meter stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } slen = ntohs(src->len) - sizeof(struct ofp_meter_stats); s = (struct ofl_meter_stats *) malloc(sizeof(struct ofl_meter_stats)); s->meter_id = ntohl(src->meter_id); s->len = ntohs(src->len); s->flow_count = ntohl(src->flow_count); s->packet_in_count = ntoh64(src->packet_in_count); s->byte_in_count = ntoh64(src->byte_in_count); s->duration_sec = htonl(src->duration_sec); s->duration_nsec = htonl(src->duration_nsec); error = ofl_utils_count_ofp_meter_band_stats(src->band_stats, slen, &s->meter_bands_num); if (error) { free(s); return error; } s->band_stats = (struct ofl_meter_band_stats **)malloc(s->meter_bands_num * sizeof(struct ofl_meter_band_stats *)); c = src->band_stats; for (i = 0; i < s->meter_bands_num; i++) { error = ofl_structs_meter_band_stats_unpack(c, &slen, &(s->band_stats[i])); if (error) { OFL_UTILS_FREE_ARR(s->band_stats, i); free(s); return error; } c = (struct ofp_meter_band_stats *)((uint8_t *)c + sizeof(struct ofp_meter_band_stats)); } if (slen != 0) { *len = *len - ntohs(src->len) + slen; OFL_LOG_WARN(LOG_MODULE, "The received meter stats contained extra bytes (%zu).", slen); ofl_structs_free_meter_stats(s); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->len); *dst = s; return 0; }
ofl_err ofl_structs_table_features_unpack(struct ofp_table_features *src,size_t *len, struct ofl_table_features **dst, struct ofl_exp *exp){ struct ofl_table_features *feat; uint8_t *prop; ofl_err error; size_t plen, i; if(*len < sizeof(struct ofp_table_features)){ OFL_LOG_WARN(LOG_MODULE, "Received table feature is too short (%zu).", *len); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } if(*len < ntohs(src->length)){ OFL_LOG_WARN(LOG_MODULE, "Received table_feature has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } feat = (struct ofl_table_features*) malloc(sizeof(struct ofl_table_features)); feat->length = ntohs(src->length); feat->table_id = src->table_id; feat->name = malloc(OFP_MAX_TABLE_NAME_LEN); strncpy(feat->name, src->name, OFP_MAX_TABLE_NAME_LEN); feat->metadata_match = ntoh64(src->metadata_match); feat->metadata_write = ntoh64(src->metadata_write); feat->config = ntohl(src->config); feat->max_entries = ntohl(src->max_entries); plen = ntohs(src->length) - sizeof(struct ofp_table_features); error = ofl_utils_count_ofp_table_features_properties((uint8_t*) src->properties, plen, &feat->properties_num); if (error) { free(feat); return error; } feat->properties = (struct ofl_table_feature_prop_header**) malloc(sizeof(struct ofl_table_feature_prop_header *) * feat->properties_num); prop = (uint8_t*) src->properties; for(i = 0; i < feat->properties_num; i++){ error = ofl_structs_table_properties_unpack((struct ofp_table_feature_prop_header*) prop, &plen, &feat->properties[i], exp); if (error) { *len = *len - ntohs(src->length) + plen; /*OFL_UTILS_FREE_ARR_FUN2(b->actions, i, ofl_actions_free, exp);*/ free(feat); return error; } prop += ROUND_UP(ntohs(((struct ofp_table_feature_prop_header*) prop)->length),8); } *len -= ntohs(src->length); *dst = feat; return 0; }
ofl_err ofl_structs_meter_config_unpack(struct ofp_meter_config *src, size_t *len, struct ofl_meter_config **dst) { struct ofl_meter_config *s; struct ofp_meter_band_header *b; ofl_err error; size_t slen; size_t i; if (*len < sizeof(struct ofp_meter_config)) { OFL_LOG_WARN(LOG_MODULE, "Received meter config 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 meter config reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } slen = ntohs(src->length) - sizeof(struct ofp_meter_config); s = (struct ofl_meter_config *) malloc(sizeof(struct ofl_meter_config)); s->meter_id = ntohl(src->meter_id); s->length = ntohs(src->length); s->flags = ntohs(src->flags); error = ofl_utils_count_ofp_meter_bands(src->bands, slen, &s->meter_bands_num); if (error) { free(s); return error; } s->bands = (struct ofl_meter_band_header **)malloc(s->meter_bands_num * sizeof(struct ofl_meter_band_header *)); b= src->bands; for (i = 0; i < s->meter_bands_num; i++) { error = ofl_structs_meter_band_unpack(b, &slen, &(s->bands[i])); if (error) { OFL_UTILS_FREE_ARR(s->bands, i); free(s); return error; } b = (struct ofp_meter_band_header *)((uint8_t *)b + ntohs(b->len)); } if (slen != 0) { *len = *len - ntohs(src->length) + slen; OFL_LOG_WARN(LOG_MODULE, "The received meter config contained extra bytes (%zu).", slen); //ofl_structs_free_meter_stats(s); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= ntohs(src->length); *dst = s; return 0; }
static ofl_err ofl_msg_unpack_packet_in(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, char *errbuf) { struct ofp_packet_in *sp; struct ofl_msg_packet_in *dp; if (*len < sizeof(struct ofp_packet_in)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *ps = ofl_port_to_string(ntohl(sp->in_port)); snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *ts = ofl_table_to_string(sp->table_id); snprintf(errbuf, OFL_ERRBUF_SIZE, "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; }
static ofl_err ofl_msg_unpack_port_status(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { struct ofp_port_status *ss; struct ofl_msg_port_status *ds; ofl_err error; if (*len < sizeof(struct ofp_port_status)) { OFL_LOG_WARN(LOG_MODULE, "Received PORT_STATUS message has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= (sizeof(struct ofp_port_status) - sizeof(struct ofp_port)); ss = (struct ofp_port_status *)src; ds = (struct ofl_msg_port_status *)malloc(sizeof(struct ofl_msg_port_status)); ds->reason = (enum ofp_port_reason)(ss->reason); error = ofl_structs_port_unpack(&(ss->desc), len, &(ds->desc)); if (error) { free(ds); return error; } *msg = (struct ofl_msg_header *)ds; return 0; }
static ofl_err ofl_msg_unpack_port_status(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, char *errbuf) { struct ofp_port_status *ss; struct ofl_msg_port_status *ds; ofl_err error; if (*len < sizeof(struct ofp_port_status)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received PORT_STATUS message has invalid length (%zu).", *len); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= (sizeof(struct ofp_port_status) - sizeof(struct ofp_port)); ss = (struct ofp_port_status *)src; ds = (struct ofl_msg_port_status *)malloc(sizeof(struct ofl_msg_port_status)); ds->reason = ss->reason; error = ofl_structs_port_unpack(&(ss->desc), len, &(ds->desc), errbuf); if (error) { free(ds); return error; } *msg = (struct ofl_msg_header *)ds; return 0; }
ofl_err ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struct ofl_packet_queue **dst, char *errbuf) { struct ofl_packet_queue *q; struct ofp_queue_prop_header *prop; ofl_err error; size_t i; if (*len < ntohs(src->len)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received packet queue has invalid length (%zu).", *len); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_packet_queue); q = (struct ofl_packet_queue *)malloc(sizeof(struct ofl_packet_queue)); q->queue_id = ntohl(src->queue_id); error = ofl_utils_count_ofp_queue_props((uint8_t *)src->properties, *len, &q->properties_num, errbuf); if (error) { free(q); return error; } q->properties = (struct ofl_queue_prop_header **)malloc(q->properties_num * sizeof(struct ofl_queue_prop_header *)); prop = src->properties; for (i = 0; i < q->properties_num; i++) { ofl_structs_queue_prop_unpack(prop, len, &(q->properties[i]), errbuf); //TODO error prop = (struct ofp_queue_prop_header *)((uint8_t *)prop + ntohs(prop->len)); } *dst = q; return 0; }
static ofl_err ofl_msg_unpack_stats_request_flow(struct ofp_stats_request *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp, char *errbuf) { struct ofp_flow_stats_request *sm; struct ofl_msg_stats_request_flow *dm; ofl_err error = 0; // ofp_stats_request length was checked at ofl_msg_unpack_stats_request if (*len < (sizeof(struct ofp_flow_stats_request) - sizeof(struct ofp_match))) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received FLOW stats request has invalid length (%zu).", *len); } return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } *len -= (sizeof(struct ofp_flow_stats_request) - sizeof(struct ofp_match)); sm = (struct ofp_flow_stats_request *)os->body; dm = (struct ofl_msg_stats_request_flow *)malloc(sizeof(struct ofl_msg_stats_request_flow)); dm->table_id = sm->table_id; dm->out_port = ntohl(sm->out_port); dm->out_group = ntohl(sm->out_group); dm->cookie = ntoh64(sm->cookie); dm->cookie_mask = ntoh64(sm->cookie_mask); error = ofl_structs_match_unpack(&(sm->match), len, &(dm->match), exp, errbuf); if (error) { free(dm); return error; } *msg = (struct ofl_msg_header *)dm; return 0; }
static ofl_err ofl_msg_unpack_flow_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { struct ofp_flow_mod *sm; struct ofl_msg_flow_mod *dm; struct ofp_instruction *inst; ofl_err error; size_t i; if (*len < (sizeof(struct ofp_flow_mod) - sizeof(struct ofp_match))) { OFL_LOG_WARN(LOG_MODULE, "Received FLOW_MOD message has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= (sizeof(struct ofp_flow_mod) - sizeof(struct ofp_match)); sm = (struct ofp_flow_mod *)src; dm = (struct ofl_msg_flow_mod *)malloc(sizeof(struct ofl_msg_flow_mod)); dm->cookie = ntoh64(sm->cookie); dm->cookie_mask = ntoh64(sm->cookie_mask); dm->table_id = sm->table_id; dm->command = (enum ofp_flow_mod_command)sm->command; dm->idle_timeout = ntohs( sm->idle_timeout); dm->hard_timeout = ntohs( sm->hard_timeout); dm->priority = ntohs( sm->priority); dm->buffer_id = ntohl( sm->buffer_id); dm->out_port = ntohl( sm->out_port); dm->out_group = ntohl( sm->out_group); dm->flags = ntohs( sm->flags); error = ofl_structs_match_unpack(&(sm->match), len, &(dm->match), exp); if (error) { free(dm); return error; } error = ofl_utils_count_ofp_instructions(&(sm->instructions), *len, &dm->instructions_num); if (error) { ofl_structs_free_match(dm->match, exp); free(dm); return error; } dm->instructions = (struct ofl_instruction_header **)malloc(dm->instructions_num * sizeof(struct ofl_instruction_header *)); inst = sm->instructions; for (i = 0; i < dm->instructions_num; i++) { error = ofl_structs_instructions_unpack(inst, len, &(dm->instructions[i]), exp); if (error) { OFL_UTILS_FREE_ARR_FUN2(dm->instructions, i, ofl_structs_free_instruction, exp); ofl_structs_free_match(dm->match, exp); free(dm); return error; } inst = (struct ofp_instruction *)((uint8_t *)inst + ntohs(inst->len)); } *msg = (struct ofl_msg_header *)dm; return 0; }
ofl_err ATN_ofl_exp_action_unpack (struct ofp_action_header *src, size_t *len, struct ofl_action_header **dst) { struct ATN_ofp_action_exp *sa = (struct ATN_ofp_action_exp *)src; struct ATN_ofl_action_exp *da = malloc(sizeof(struct ATN_ofl_action_exp)); if (*len < sizeof(struct ATN_ofp_action_exp)) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER message has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } switch (ntohl(sa->exp_type)) { case ATN_OFPAT_PUSH_L2_GRE_HEADER: { da->experimenter = ntohl(sa->header.experimenter); da->exp_type = ntohl(sa->exp_type); break; } case ATN_OFPAT_POP_L2_GRE_HEADER:{ da->experimenter = ntohl(sa->header.experimenter); da->exp_type = ntohl(sa->exp_type); break; } } *len -= sizeof(struct ATN_ofp_action_exp); *dst = (struct ofl_action_header*) da; return 0; }
ofl_err ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struct ofl_packet_queue **dst) { struct ofl_packet_queue *q; struct ofp_queue_prop_header *prop; ofl_err error; size_t i; if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received packet queue has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_packet_queue); q = (struct ofl_packet_queue *)malloc(sizeof(struct ofl_packet_queue)); q->queue_id = ntohl(src->queue_id); error = ofl_utils_count_ofp_queue_props((uint8_t *)src->properties, ntohs(src->len)-sizeof(struct ofp_packet_queue)/**len*/, &q->properties_num); if (error) { free(q); return error; } q->properties = (struct ofl_queue_prop_header **)malloc(q->properties_num * sizeof(struct ofl_queue_prop_header *)); prop = src->properties; for (i = 0; i < q->properties_num; i++) { ofl_structs_queue_prop_unpack(prop, len, &(q->properties[i])); prop = (struct ofp_queue_prop_header *)((uint8_t *)prop + ntohs(prop->len)); } *dst = q; return 0; }
ofl_err ofl_structs_queue_prop_unpack(struct ofp_queue_prop_header *src, size_t *len, struct ofl_queue_prop_header **dst, char *errbuf) { if (*len < sizeof(struct ofp_action_header)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received queue property is too short (%zu).", *len); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } if (*len < ntohs(src->len)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received queue property has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); } return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } switch (ntohs(src->property)) { case OFPQT_MIN_RATE: { struct ofp_queue_prop_min_rate *sp = (struct ofp_queue_prop_min_rate *)src; struct ofl_queue_prop_min_rate *dp = (struct ofl_queue_prop_min_rate *)malloc(sizeof(struct ofl_queue_prop_min_rate)); if (*len < sizeof(struct ofp_queue_prop_min_rate)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received MIN_RATE queue property has invalid length (%zu).", *len); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } *len -= sizeof(struct ofp_queue_prop_min_rate); dp->rate = ntohs(sp->rate); *dst = (struct ofl_queue_prop_header *)dp; break; } default: { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "Received unknown queue prop type."); } return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); } } (*dst)->type = (enum ofp_queue_properties)ntohs(src->property); return 0; }
/* Handles flow mod messages with ADD command. */ static ofl_err flow_table_add(struct flow_table *table, struct ofl_msg_flow_mod *mod, bool check_overlap, bool *match_kept, bool *insts_kept) { // Note: new entries will be placed behind those with equal priority struct flow_entry *entry, *new_entry; LIST_FOR_EACH (entry, struct flow_entry, match_node, &table->match_entries) { if (check_overlap && flow_entry_overlaps(entry, mod)) { return ofl_error(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP); } /* if the entry equals, replace the old one */ if (flow_entry_matches(entry, mod, true/*strict*/, false/*check_cookie*/)) { new_entry = flow_entry_create(table->dp, table, mod); *match_kept = true; *insts_kept = true; /* NOTE: no flow removed message should be generated according to spec. */ list_replace(&new_entry->match_node, &entry->match_node); list_remove(&entry->hard_node); list_remove(&entry->idle_node); flow_entry_destroy(entry); add_to_timeout_lists(table, new_entry); return 0; } if (mod->priority > entry->stats->priority) { break; } } if (table->stats->active_count == FLOW_TABLE_MAX_ENTRIES) { return ofl_error(OFPET_FLOW_MOD_FAILED, OFPFMFC_TABLE_FULL); } table->stats->active_count++; new_entry = flow_entry_create(table->dp, table, mod); *match_kept = true; *insts_kept = true; list_insert(&entry->match_node, &new_entry->match_node); add_to_timeout_lists(table, new_entry); return 0; }
ofl_err ofl_exp_stats_reply_unpack (struct ofp_multipart_reply *os, uint8_t *buf, size_t *len, struct ofl_msg_multipart_reply_header **msg, struct ofl_exp *exp){ struct ofp_experimenter_stats_header *ext = (struct ofp_experimenter_stats_header *)os->body; if (*len < sizeof(struct ofp_experimenter_stats_header)) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER message is shorter than ofp_experimenter_stats_header."); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } switch (ntohl(ext->experimenter)) { case (OPENSTATE_VENDOR_ID): { return ofl_exp_openstate_stats_reply_unpack(os, buf, len, (struct ofl_msg_multipart_reply_header **)msg, exp); } default: { OFL_LOG_WARN(LOG_MODULE, "Trying to unpack unknown EXPERIMENTER message (%u).", ntohl(ext->experimenter)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_EXPERIMENTER); } } }
ofl_err ofl_exp_stats_req_unpack (struct ofp_multipart_request const *os, uint8_t const *buf, size_t *len, struct ofl_msg_multipart_request_header **msg, struct ofl_exp const *exp) { struct ofp_experimenter_stats_header *ext = (struct ofp_experimenter_stats_header *)os->body; if (*len < sizeof(struct ofp_experimenter_stats_header)) { OFL_LOG_WARN(LOG_MODULE, "Received EXPERIMENTER message is shorter than ofp_experimenter_stats_header."); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } switch (ntohl(ext->experimenter)) { case (BEBA_VENDOR_ID): { return ofl_exp_beba_stats_req_unpack(os, buf, len, msg, exp); } default: { OFL_LOG_WARN(LOG_MODULE, "Trying to unpack unknown EXPERIMENTER message %"PRIx32".", ntohl(ext->experimenter)); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_EXPERIMENTER); } } }
ofl_err ofl_structs_port_stats_unpack(struct ofp_port_stats *src, size_t *len, struct ofl_port_stats **dst, char *errbuf) { struct ofl_port_stats *p; if (*len < sizeof(struct ofp_port_stats)) { if (errbuf != NULL) { snprintf(errbuf, OFL_ERRBUF_SIZE, "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 (errbuf != NULL) { char *ps = ofl_port_to_string(ntohl(src->port_no)); snprintf(errbuf, OFL_ERRBUF_SIZE, "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); *dst = p; return 0; }