void indigo_core_flow_removed(indigo_fi_flow_removed_t reason, indigo_fi_flow_stats_t *stats) { ft_entry_t *entry; if (!ind_core_init_done) { return; } LOG_TRACE("Async flow removed. reason %d. id " INDIGO_FLOW_ID_PRINTF_FORMAT, reason, INDIGO_FLOW_ID_PRINTF_ARG((indigo_cookie_t) stats->flow_id)); /* After entry look up, this looks like ind_core_flow_entry_delete */ entry = ft_lookup(ind_core_ft, stats->flow_id); if (entry == NULL) { LOG_TRACE("Async flow removed: did not find entry in SM table. id " INDIGO_FLOW_ID_PRINTF_FORMAT, INDIGO_FLOW_ID_PRINTF_ARG((indigo_cookie_t) stats->flow_id)); return; } process_flow_removal(entry, stats, reason); }
static void process_flow_removal(ft_entry_t *entry, indigo_fi_flow_stats_t *final_stats, indigo_fi_flow_removed_t reason) { indigo_error_t rv; if (entry->flags & OF_FLOW_MOD_FLAG_SEND_FLOW_REM) { /* See OF spec 1.0.1, section 3.5, page 6 */ if (reason != INDIGO_FLOW_REMOVED_OVERWRITE) { if (final_stats != NULL) { INDIGO_ASSERT(final_stats->flow_id == entry->id); entry->packets = final_stats->packets; entry->bytes = final_stats->bytes; } else { entry->packets = (uint64_t)-1; entry->bytes = (uint64_t)-1; } send_flow_removed_message(entry, reason); } } rv = ft_delete(ind_core_ft, entry); if (rv != INDIGO_ERROR_NONE) { LOG_ERROR("Error deleting flow from state mgr. id: " INDIGO_FLOW_ID_PRINTF_FORMAT, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); } LOG_TRACE("Flow table now has %d entries", FT_STATUS(ind_core_ft)->current_count); }
static void expire_flow(ft_entry_t *entry, int reason) { if (reason == INDIGO_FLOW_REMOVED_HARD_TIMEOUT) { LOG_TRACE("Hard TO (%d): " INDIGO_FLOW_ID_PRINTF_FORMAT, entry->hard_timeout, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); ind_core_flow_entry_delete(entry, reason, INDIGO_CXN_ID_UNSPECIFIED); } else if (reason == OF_FLOW_REMOVED_REASON_IDLE_TIMEOUT) { int rv; bool hit; /* Get hit status for idle timeouts */ ind_core_table_t *table = ind_core_table_get(entry->table_id); if (table != NULL) { rv = table->ops->entry_hit_status_get(table->priv, INDIGO_CXN_ID_UNSPECIFIED, entry->priv, &hit); } else { rv = indigo_fwd_flow_hit_status_get(entry->id, &hit); } if (rv != INDIGO_ERROR_NONE) { LOG_ERROR("Failed to get hit status for flow " INDIGO_FLOW_ID_PRINTF_FORMAT": %s", entry->id, indigo_strerror(rv)); return; } if (hit || entry->flags & OF_FLOW_MOD_FLAG_BSN_SEND_IDLE) { /* Reinsert entry into the expiration list */ entry->last_counter_change = INDIGO_CURRENT_TIME; ind_core_expiration_remove(entry); ind_core_expiration_add(entry); } if (!hit) { if (entry->flags & OF_FLOW_MOD_FLAG_BSN_SEND_IDLE) { send_idle_notification(entry); } else { LOG_TRACE("Idle TO (%d): " INDIGO_FLOW_ID_PRINTF_FORMAT, entry->idle_timeout, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); ind_core_flow_entry_delete(entry, reason, INDIGO_CXN_ID_UNSPECIFIED); } } } }
void ind_core_flow_entry_delete(ft_entry_t *entry, indigo_fi_flow_removed_t reason, indigo_cxn_id_t cxn_id) { indigo_error_t rv; indigo_fi_flow_stats_t flow_stats; LOG_TRACE("Removing flow " INDIGO_FLOW_ID_PRINTF_FORMAT, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); rv = indigo_fwd_flow_delete(entry->id, &flow_stats); if (rv != INDIGO_ERROR_NONE) { LOG_ERROR("Error deleting flow, id " INDIGO_FLOW_ID_PRINTF_FORMAT, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); /* Ignoring failure */ } process_flow_removal(entry, &flow_stats, reason); }
/** * Timer operation to expire flows. * * Calls indigo_fwd_flow_stats_get for each flow in the table. The expiration * is done in flow_expiration_timer_cb when the reply is received. * * Ignore this call if the module is not enabled. */ static void flow_expiration_timer(void *cookie) { ft_entry_t *entry; list_links_t *cur, *next; indigo_time_t current_time = INDIGO_CURRENT_TIME; if (!ind_core_module_enabled) { return; } FT_ITER(ind_core_ft, entry, cur, next) { indigo_error_t rv; indigo_fi_flow_stats_t flow_stats; if (entry->hard_timeout > 0) { uint32_t delta; delta = INDIGO_TIME_DIFF_ms(entry->insert_time, current_time) / 1000; if (delta >= entry->hard_timeout) { LOG_TRACE("Hard TO (%d): " INDIGO_FLOW_ID_PRINTF_FORMAT, entry->hard_timeout, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); ind_core_flow_entry_delete(entry, INDIGO_FLOW_REMOVED_HARD_TIMEOUT, INDIGO_CXN_ID_UNSPECIFIED); continue; } } /* Update local copy of counters */ /* Only used currently for idle timeouts */ if (entry->idle_timeout > 0) { rv = indigo_fwd_flow_stats_get(entry->id, &flow_stats); if (rv != INDIGO_ERROR_NONE) { LOG_ERROR("Failed to get stats for flow "INDIGO_FLOW_ID_PRINTF_FORMAT": %d", entry->id, rv); continue; } if (entry->packets != flow_stats.packets) { entry->packets = flow_stats.packets; entry->last_counter_change = current_time; } if (entry->bytes != flow_stats.bytes) { entry->bytes = flow_stats.bytes; entry->last_counter_change = current_time; } } if (entry->idle_timeout > 0) { uint32_t delta; delta = INDIGO_TIME_DIFF_ms(entry->last_counter_change, current_time) / 1000; if (delta >= entry->idle_timeout) { LOG_TRACE("Idle TO (%d): " INDIGO_FLOW_ID_PRINTF_FORMAT, entry->idle_timeout, INDIGO_FLOW_ID_PRINTF_ARG(entry->id)); ind_core_flow_entry_delete(entry, INDIGO_FLOW_REMOVED_IDLE_TIMEOUT, INDIGO_CXN_ID_UNSPECIFIED); continue; } } }