xlate_learn_action(struct xlate_ctx *ctx,
const struct ofpact_learn *learn)
{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
- struct ofputil_flow_mod fm;
- uint64_t ofpacts_stub[1024 / 8];
+ struct ofputil_flow_mod *fm;
struct ofpbuf ofpacts;
- int error;
ctx->xout->has_learn = true;
return;
}
- ofpbuf_use_stack(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
- learn_execute(learn, &ctx->xin->flow, &fm, &ofpacts);
-
- error = ofproto_dpif_flow_mod(ctx->xbridge->ofproto, &fm);
- if (error && !VLOG_DROP_WARN(&rl)) {
- VLOG_WARN("learning action failed to modify flow table (%s)",
- ofperr_get_name(error));
- }
+ fm = xmalloc(sizeof *fm);
+ ofpbuf_init(&ofpacts, 0);
+ learn_execute(learn, &ctx->xin->flow, fm, &ofpacts);
- ofpbuf_uninit(&ofpacts);
+ ofproto_dpif_flow_mod(ctx->xbridge->ofproto, fm);
}
/* Reduces '*timeout' to no more than 'max'. A value of zero in either case
COVERAGE_DEFINE(facet_unexpected);
COVERAGE_DEFINE(facet_suppress);
COVERAGE_DEFINE(subfacet_install_fail);
+COVERAGE_DEFINE(flow_mod_overflow);
/* Number of implemented OpenFlow tables. */
enum { N_TABLES = 255 };
static int set_cfm(struct ofport *, const struct cfm_settings *);
static void ofport_update_peer(struct ofport_dpif *);
static void run_fast_rl(void);
+static int run_fast(struct ofproto *);
struct dpif_completion {
struct list list_node;
/* Per ofproto's dpif stats. */
uint64_t n_hit;
uint64_t n_missed;
+
+ /* Work queues. */
+ struct ovs_mutex flow_mod_mutex;
+ struct list flow_mods OVS_GUARDED;
+ size_t n_flow_mods OVS_GUARDED;
};
/* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only
/* Initial mappings of port to bridge mappings. */
static struct shash init_ofp_ports = SHASH_INITIALIZER(&init_ofp_ports);
-int
+/* Executes and takes ownership of 'fm'. */
+void
ofproto_dpif_flow_mod(struct ofproto_dpif *ofproto,
struct ofputil_flow_mod *fm)
{
- return ofproto_flow_mod(&ofproto->up, fm);
+ ovs_mutex_lock(&ofproto->flow_mod_mutex);
+ if (ofproto->n_flow_mods > 1024) {
+ ovs_mutex_unlock(&ofproto->flow_mod_mutex);
+ COVERAGE_INC(flow_mod_overflow);
+ free(fm->ofpacts);
+ free(fm);
+ return;
+ }
+
+ list_push_back(&ofproto->flow_mods, &fm->list_node);
+ ofproto->n_flow_mods++;
+ ovs_mutex_unlock(&ofproto->flow_mod_mutex);
}
void
if (time_msec() >= port_rl) {
struct ofproto_dpif *ofproto;
- struct ofport_dpif *ofport;
HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-
- HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
- port_run_fast(ofport);
- }
+ run_fast(&ofproto->up);
}
port_rl = time_msec() + 200;
}
list_init(&ofproto->completions);
+ ovs_mutex_init(&ofproto->flow_mod_mutex, PTHREAD_MUTEX_NORMAL);
+ ovs_mutex_lock(&ofproto->flow_mod_mutex);
+ list_init(&ofproto->flow_mods);
+ ofproto->n_flow_mods = 0;
+ ovs_mutex_unlock(&ofproto->flow_mod_mutex);
+
ofproto_dpif_unixctl_init();
hmap_init(&ofproto->vlandev_map);
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct rule_dpif *rule, *next_rule;
+ struct ofputil_flow_mod *fm, *next_fm;
struct oftable *table;
ofproto->backer->need_revalidate = REV_RECONFIGURE;
}
}
+ ovs_mutex_lock(&ofproto->flow_mod_mutex);
+ LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &ofproto->flow_mods) {
+ list_remove(&fm->list_node);
+ ofproto->n_flow_mods--;
+ free(fm->ofpacts);
+ free(fm);
+ }
+ ovs_mutex_unlock(&ofproto->flow_mod_mutex);
+ ovs_mutex_destroy(&ofproto->flow_mod_mutex);
+
mbridge_unref(ofproto->mbridge);
netflow_destroy(ofproto->netflow);
run_fast(struct ofproto *ofproto_)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct ofputil_flow_mod *fm, *next;
struct ofport_dpif *ofport;
+ struct list flow_mods;
/* Do not perform any periodic activity required by 'ofproto' while
* waiting for flow restore to complete. */
return 0;
}
+ ovs_mutex_lock(&ofproto->flow_mod_mutex);
+ if (ofproto->n_flow_mods) {
+ flow_mods = ofproto->flow_mods;
+ list_moved(&flow_mods);
+ list_init(&ofproto->flow_mods);
+ ofproto->n_flow_mods = 0;
+ } else {
+ list_init(&flow_mods);
+ }
+ ovs_mutex_unlock(&ofproto->flow_mod_mutex);
+
+ LIST_FOR_EACH_SAFE (fm, next, list_node, &flow_mods) {
+ int error = ofproto_flow_mod(&ofproto->up, fm);
+ if (error && !VLOG_DROP_WARN(&rl)) {
+ VLOG_WARN("learning action failed to modify flow table (%s)",
+ ofperr_get_name(error));
+ }
+
+ list_remove(&fm->list_node);
+ free(fm->ofpacts);
+ free(fm);
+ }
+
HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
port_run_fast(ofport);
}