const struct flow *,
const struct nlattr *odp_actions,
size_t actions_len,
- struct ofpbuf *packet);
+ struct ofpbuf *packet, bool clone);
static void facet_flush_stats(struct ofproto_dpif *, struct facet *);
const struct nlattr *key,
size_t key_len, ovs_be16 initial_tci);
static struct subfacet *subfacet_find(struct ofproto_dpif *,
- const struct nlattr *key, size_t key_len,
- const struct flow *);
+ const struct nlattr *key, size_t key_len);
static void subfacet_destroy(struct ofproto_dpif *, struct subfacet *);
static void subfacet_destroy__(struct ofproto_dpif *, struct subfacet *);
static void subfacet_reset_dp_stats(struct subfacet *,
};
struct ofproto_dpif {
+ struct hmap_node all_ofproto_dpifs_node; /* In 'all_ofproto_dpifs'. */
struct ofproto up;
struct dpif *dpif;
int max_ports;
* for debugging the asynchronous flow_mod implementation.) */
static bool clogged;
+/* All existing ofproto_dpif instances, indexed by ->up.name. */
+static struct hmap all_ofproto_dpifs = HMAP_INITIALIZER(&all_ofproto_dpifs);
+
static void ofproto_dpif_unixctl_init(void);
static struct ofproto_dpif *
hmap_init(&ofproto->vlandev_map);
hmap_init(&ofproto->realdev_vid_map);
+ hmap_insert(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node,
+ hash_string(ofproto->up.name, 0));
+
*n_tablesp = N_TABLES;
return 0;
}
struct classifier *table;
int i;
+ hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
complete_operations(ofproto);
OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
\f
/* Bundles. */
-/* Expires all MAC learning entries associated with 'port' and forces ofproto
- * to revalidate every flow. */
+/* Expires all MAC learning entries associated with 'bundle' and forces its
+ * ofproto to revalidate every flow.
+ *
+ * Normally MAC learning entries are removed only from the ofproto associated
+ * with 'bundle', but if 'all_ofprotos' is true, then the MAC learning entries
+ * are removed from every ofproto. When patch ports and SLB bonds are in use
+ * and a VM migration happens and the gratuitous ARPs are somehow lost, this
+ * avoids a MAC_ENTRY_IDLE_TIME delay before the migrated VM can communicate
+ * with the host from which it migrated. */
static void
-bundle_flush_macs(struct ofbundle *bundle)
+bundle_flush_macs(struct ofbundle *bundle, bool all_ofprotos)
{
struct ofproto_dpif *ofproto = bundle->ofproto;
struct mac_learning *ml = ofproto->ml;
ofproto->need_revalidate = true;
LIST_FOR_EACH_SAFE (mac, next_mac, lru_node, &ml->lrus) {
if (mac->port.p == bundle) {
+ if (all_ofprotos) {
+ struct ofproto_dpif *o;
+
+ HMAP_FOR_EACH (o, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+ if (o != ofproto) {
+ struct mac_entry *e;
+
+ e = mac_learning_lookup(o->ml, mac->mac, mac->vlan,
+ NULL);
+ if (e) {
+ tag_set_add(&o->revalidate_set, e->tag);
+ mac_learning_expire(o->ml, e);
+ }
+ }
+ }
+ }
+
mac_learning_expire(ml, mac);
}
}
bundle_del_port(port);
}
- bundle_flush_macs(bundle);
+ bundle_flush_macs(bundle, true);
hmap_remove(&ofproto->bundles, &bundle->hmap_node);
free(bundle->name);
free(bundle->trunks);
/* If we changed something that would affect MAC learning, un-learn
* everything on this port and force flow revalidation. */
if (need_flush) {
- bundle_flush_macs(bundle);
+ bundle_flush_macs(bundle, false);
}
return 0;
miss->initial_tci);
LIST_FOR_EACH_SAFE (packet, next_packet, list_node, &miss->packets) {
+ struct dpif_flow_stats stats;
+
list_remove(&packet->list_node);
ofproto->n_matches++;
if (!facet->may_install || !subfacet->actions) {
subfacet_make_actions(ofproto, subfacet, packet);
}
+
+ /* Credit statistics to subfacet for this packet. We must do this now
+ * because execute_controller_action() below may destroy 'packet'. */
+ dpif_flow_stats_extract(&facet->flow, packet, &stats);
+ subfacet_update_stats(ofproto, subfacet, &stats);
+
if (!execute_controller_action(ofproto, &facet->flow,
subfacet->actions,
- subfacet->actions_len, packet)) {
+ subfacet->actions_len, packet, true)) {
struct flow_miss_op *op = &ops[(*n_ops)++];
struct dpif_execute *execute = &op->dpif_op.execute;
upcall->key, upcall->key_len,
&flow, &initial_tci);
if (fitness == ODP_FIT_ERROR) {
+ ofpbuf_delete(upcall->packet);
continue;
}
flow_extract(upcall->packet, flow.priority, flow.tun_id,
upcall->key_len, &flow,
&initial_tci);
if (fitness == ODP_FIT_ERROR) {
+ ofpbuf_delete(upcall->packet);
return;
}
&flow, false);
} else {
VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata);
+ ofpbuf_delete(upcall->packet);
}
}
dpif_flow_dump_start(&dump, p->dpif);
while (dpif_flow_dump_next(&dump, &key, &key_len, NULL, NULL, &stats)) {
- enum odp_key_fitness fitness;
struct subfacet *subfacet;
- struct flow flow;
-
- fitness = odp_flow_key_to_flow(key, key_len, &flow);
- if (fitness == ODP_FIT_ERROR) {
- continue;
- }
- subfacet = subfacet_find(p, key, key_len, &flow);
+ subfacet = subfacet_find(p, key, key_len);
if (subfacet && subfacet->installed) {
struct facet *facet = subfacet->facet;
facet_account(p, facet);
facet_push_stats(facet);
} else {
+ if (!VLOG_DROP_WARN(&rl)) {
+ struct ds s;
+
+ ds_init(&s);
+ odp_flow_key_format(key, key_len, &s);
+ VLOG_WARN("unexpected flow from datapath %s", ds_cstr(&s));
+ ds_destroy(&s);
+ }
+
+ COVERAGE_INC(facet_unexpected);
/* There's a flow in the datapath that we know nothing about, or a
* flow that shouldn't be installed but was anyway. Delete it. */
- COVERAGE_INC(facet_unexpected);
dpif_flow_del(p->dpif, key, key_len, NULL);
}
}
free(facet);
}
+/* If the 'actions_len' bytes of actions in 'odp_actions' are just a single
+ * OVS_ACTION_ATTR_USERSPACE action, executes it internally and returns true.
+ * Otherwise, returns false without doing anything.
+ *
+ * If 'clone' is true, the caller always retains ownership of 'packet'.
+ * Otherwise, ownership is transferred to this function if it returns true. */
static bool
execute_controller_action(struct ofproto_dpif *ofproto,
const struct flow *flow,
const struct nlattr *odp_actions, size_t actions_len,
- struct ofpbuf *packet)
+ struct ofpbuf *packet, bool clone)
{
if (actions_len
&& odp_actions->nla_type == OVS_ACTION_ATTR_USERSPACE
nla = nl_attr_find_nested(odp_actions, OVS_USERSPACE_ATTR_USERDATA);
send_packet_in_action(ofproto, packet, nl_attr_get_u64(nla), flow,
- false);
+ clone);
return true;
} else {
return false;
int error;
if (execute_controller_action(ofproto, flow, odp_actions, actions_len,
- packet)) {
+ packet, false)) {
return true;
}
* 'flow'. Returns the subfacet if one exists, otherwise NULL. */
static struct subfacet *
subfacet_find(struct ofproto_dpif *ofproto,
- const struct nlattr *key, size_t key_len,
- const struct flow *flow)
+ const struct nlattr *key, size_t key_len)
{
uint32_t key_hash = odp_flow_key_hash(key, key_len);
+ enum odp_key_fitness fitness;
+ struct flow flow;
+
+ fitness = odp_flow_key_to_flow(key, key_len, &flow);
+ if (fitness == ODP_FIT_ERROR) {
+ return NULL;
+ }
- return subfacet_find__(ofproto, key, key_len, key_hash, flow);
+ return subfacet_find__(ofproto, key, key_len, key_hash, &flow);
}
/* Uninstalls 'subfacet' from the datapath, if it is installed, removes it from
}
ofport = get_odp_port(ofproto, nl_attr_get_u32(a));
- mirrors |= ofport ? ofport->bundle->dst_mirrors : 0;
+ if (ofport && ofport->bundle) {
+ mirrors |= ofport->bundle->dst_mirrors;
+ }
}
if (!mirrors) {
static struct ofproto_dpif *
ofproto_dpif_lookup(const char *name)
{
- struct ofproto *ofproto = ofproto_lookup(name);
- return (ofproto && ofproto->ofproto_class == &ofproto_dpif_class
- ? ofproto_dpif_cast(ofproto)
- : NULL);
+ struct ofproto_dpif *ofproto;
+
+ HMAP_FOR_EACH_WITH_HASH (ofproto, all_ofproto_dpifs_node,
+ hash_string(name, 0), &all_ofproto_dpifs) {
+ if (!strcmp(ofproto->up.name, name)) {
+ return ofproto;
+ }
+ }
+ return NULL;
}
static void