/* 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);
    	}
    }
}
Exemple #3
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[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);