bool flow_entry_overlaps(struct flow_entry *entry, struct ofl_msg_flow_mod *mod) { return (entry->stats->priority == mod->priority && (mod->out_port == OFPP_ANY || flow_entry_has_out_port(entry, mod->out_port)) && (mod->out_group == OFPG_ANY || flow_entry_has_out_group(entry, mod->out_group)) && flow_entry_matches(entry, mod, false)); }
/* Handles flow mod messages with DELETE command. */ static ofl_err flow_table_delete(struct flow_table *table, struct ofl_msg_flow_mod *mod, bool strict) { struct flow_entry *entry, *next; LIST_FOR_EACH_SAFE (entry, next, struct flow_entry, match_node, &table->match_entries) { if (flow_entry_matches(entry, mod, strict, true/*check_cookie*/)) { flow_entry_remove(entry, OFPRR_DELETE); } } return 0; }
/* Handles flow mod messages with MODIFY command. If the flow doesn't exists don't do nothing*/ static ofl_err flow_table_modify(struct flow_table *table, struct ofl_msg_flow_mod *mod, bool strict, bool *insts_kept) { struct flow_entry *entry; LIST_FOR_EACH (entry, struct flow_entry, match_node, &table->match_entries) { if (flow_entry_matches(entry, mod, strict, true/*check_cookie*/)) { flow_entry_replace_instructions(entry, mod->instructions_num, mod->instructions); *insts_kept = true; } } 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; }
/* Handles flow mod messages with MODIFY command. */ static ofl_err flow_table_modify(struct flow_table *table, struct ofl_msg_flow_mod *mod, bool strict, bool *match_kept, bool *insts_kept) { struct flow_entry *entry; bool match_found; match_found = false; LIST_FOR_EACH (entry, struct flow_entry, match_node, &table->match_entries) { if (flow_entry_matches(entry, mod, strict, true/*check_cookie*/)) { flow_entry_replace_instructions(entry, mod->instructions_num, mod->instructions); *insts_kept = true; match_found = true; } } /* NOTE: if modify does not modify any entries, it acts like an add according to spec. */ if (!match_found) { return flow_table_add(table, mod, false, match_kept, insts_kept); } return 0; }