/* 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; }
/* Initializes the group references of the flow entry. */ static void init_group_refs(struct flow_entry *entry) { struct group_ref_entry *e; size_t i,j; for (i=0; i<entry->stats->instructions_num; i++) { if (entry->stats->instructions[i]->type == OFPIT_APPLY_ACTIONS || entry->stats->instructions[i]->type == OFPIT_WRITE_ACTIONS) { struct ofl_instruction_actions *ia = (struct ofl_instruction_actions *)entry->stats->instructions[i]; for (j=0; j < ia->actions_num; j++) { if (ia->actions[j]->type == OFPAT_GROUP) { struct ofl_action_group *ag = (struct ofl_action_group *)(ia->actions[j]); if (!has_group_ref(entry, ag->group_id)) { struct group_ref_entry *gre = xmalloc(sizeof(struct group_ref_entry)); gre->group_id = ag->group_id; list_insert(&entry->group_refs, &gre->node); } } } } } /* notify groups of the new referencing flow entry */ LIST_FOR_EACH(e, struct group_ref_entry, node, &entry->group_refs) { struct group_entry *group = group_table_find(entry->dp->groups, e->group_id); if (group != NULL) { group_entry_add_flow_ref(group, entry); } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to access non-existing group(%u).", e->group_id); } } }
/* Initializes the group references of the flow entry. */ static void init_group_refs(struct flow_entry *entry) { struct group_ref_entry *e; size_t i,j; for (i=0; i<entry->stats->instructions_num; i++) { if (entry->stats->instructions[i]->type == OFPIT_APPLY_ACTIONS || entry->stats->instructions[i]->type == OFPIT_WRITE_ACTIONS) { struct ofl_instruction_actions *ia = (struct ofl_instruction_actions *)entry->stats->instructions[i]; for (j=0; j < ia->actions_num; j++) { if (ia->actions[j]->type == OFPAT_GROUP) { struct ofl_action_group *ag = (struct ofl_action_group *)(ia->actions[i]); if (!has_group_ref(entry, ag->group_id)) { struct group_ref_entry *gre = xmalloc(sizeof(struct group_ref_entry)); gre->entry = group_table_find(entry->dp->groups, ag->group_id); list_insert(&entry->group_refs, &gre->node); } } } } } /* notify groups of the new referencing flow entry */ LIST_FOR_EACH(e, struct group_ref_entry, node, &entry->group_refs) { group_entry_add_flow_ref(e->entry, entry); } }
/* Deletes group references from the flow, and also deletes the flow references * from the referecenced groups. */ static void del_group_refs(struct flow_entry *entry) { struct group_ref_entry *gre, *next; LIST_FOR_EACH_SAFE(gre, next, struct group_ref_entry, node, &entry->group_refs) { struct group_entry *group = group_table_find(entry->dp->groups, gre->group_id); if (group != NULL) { group_entry_del_flow_ref(group, entry); } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to access non-existing group(%u).", gre->group_id); } list_remove(&gre->node); free(gre); } }
HMAP_FOR_EACH_SAFE(entry, next, struct group_entry, node, &table->entries) { group_entry_destroy(entry); } hmap_destroy(&table->entries); hmap_init(&table->entries); table->entries_num = 0; table->buckets_num = 0; ofl_msg_free_group_mod(mod, true, table->dp->exp); return 0; } else { struct group_entry *entry, *e; entry = group_table_find(table, mod->group_id); if (entry != NULL) { /* NOTE: The spec. does not define what happens when groups refer to groups which are being deleted. For now deleting such a group is not allowed. */ HMAP_FOR_EACH(e, struct group_entry, node, &table->entries) { if (group_entry_has_out_group(e, entry->stats->group_id)) { return ofl_error(OFPET_GROUP_MOD_FAILED, OFPGMFC_CHAINING_UNSUPPORTED); } } table->entries_num--; table->buckets_num -= entry->desc->buckets_num; hmap_remove(&table->entries, &entry->node);