* for debugging the asynchronous flow_mod implementation.) */
static bool clogged;
+/* By default, flows in the datapath are wildcarded (megaflows). They
+ * may be disabled with the "ovs-appctl dpif/disable-megaflows" command. */
+static bool enable_megaflows = true;
+
/* All existing ofproto_dpif instances, indexed by ->up.name. */
static struct hmap all_ofproto_dpifs = HMAP_INITIALIZER(&all_ofproto_dpifs);
char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
const char *dp_port;
- if (!iter->tnl_port) {
+ if (!iter->is_tunnel) {
continue;
}
}
iter->odp_port = node ? u32_to_odp(node->data) : ODPP_NONE;
- if (tnl_port_reconfigure(&iter->up, iter->odp_port,
- &iter->tnl_port)) {
+ if (tnl_port_reconfigure(iter, iter->up.netdev,
+ iter->odp_port)) {
backer->need_revalidate = REV_RECONFIGURE;
}
}
free(backer_name);
if (error) {
VLOG_ERR("failed to open datapath of type %s: %s", type,
- strerror(error));
+ ovs_strerror(error));
free(backer);
return error;
}
error = dpif_recv_set(backer->dpif, backer->recv_set_enable);
if (error) {
VLOG_ERR("failed to listen on datapath of type %s: %s",
- type, strerror(error));
+ type, ovs_strerror(error));
close_dpif_backer(backer);
return error;
}
ofproto_dpif_unixctl_init();
ofproto->has_mirrors = false;
- ofproto->has_bundle_action = false;
-
hmap_init(&ofproto->vlandev_map);
hmap_init(&ofproto->realdev_vid_map);
}
netflow_destroy(ofproto->netflow);
- dpif_sflow_destroy(ofproto->sflow);
+ dpif_sflow_unref(ofproto->sflow);
hmap_destroy(&ofproto->bundles);
- mac_learning_destroy(ofproto->ml);
+ mac_learning_unref(ofproto->ml);
classifier_destroy(&ofproto->facets);
port->may_enable = true;
port->stp_port = NULL;
port->stp_state = STP_DISABLED;
- port->tnl_port = NULL;
+ port->is_tunnel = false;
port->peer = NULL;
hmap_init(&port->priorities);
port->realdev_ofp_port = 0;
port->odp_port = dpif_port.port_no;
if (netdev_get_tunnel_config(netdev)) {
- port->tnl_port = tnl_port_add(&port->up, port->odp_port);
+ tnl_port_add(port, port->up.netdev, port->odp_port);
+ port->is_tunnel = true;
} else {
/* Sanity-check that a mapping doesn't already exist. This
* shouldn't happen for non-tunnel ports. */
* happens when the ofproto is being destroyed, since the caller
* assumes that removal of attached ports will happen as part of
* destruction. */
- if (!port->tnl_port) {
+ if (!port->is_tunnel) {
dpif_port_del(ofproto->backer->dpif, port->odp_port);
}
}
port->peer = NULL;
}
- if (port->odp_port != ODPP_NONE && !port->tnl_port) {
+ if (port->odp_port != ODPP_NONE && !port->is_tunnel) {
hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node);
}
- tnl_port_del(port->tnl_port);
+ tnl_port_del(port);
sset_find_and_delete(&ofproto->ports, devname);
sset_find_and_delete(&ofproto->ghost_ports, devname);
bundle_remove(port_);
cfm_set_netdev(port->cfm, port->up.netdev);
}
- if (port->tnl_port && tnl_port_reconfigure(&port->up, port->odp_port,
- &port->tnl_port)) {
+ if (port->is_tunnel && tnl_port_reconfigure(port, port->up.netdev,
+ port->odp_port)) {
ofproto_dpif_cast(port->up.ofproto)->backer->need_revalidate =
REV_RECONFIGURE;
}
dpif_sflow_set_options(ds, sflow_options);
} else {
if (ds) {
- dpif_sflow_destroy(ds);
+ dpif_sflow_unref(ds);
ofproto->backer->need_revalidate = REV_RECONFIGURE;
ofproto->sflow = NULL;
}
n_flow_exporters_options);
} else {
if (di) {
- dpif_ipfix_destroy(di);
+ dpif_ipfix_unref(di);
ofproto->ipfix = NULL;
}
}
error = EINVAL;
}
- cfm_destroy(ofport->cfm);
+ cfm_unref(ofport->cfm);
ofport->cfm = NULL;
return error;
}
hmap_remove(&ofproto->bundles, &bundle->hmap_node);
free(bundle->name);
free(bundle->trunks);
- lacp_destroy(bundle->lacp);
- bond_destroy(bundle->bond);
+ lacp_unref(bundle->lacp);
+ bond_unref(bundle->bond);
free(bundle);
}
}
lacp_configure(bundle->lacp, s->lacp);
} else {
- lacp_destroy(bundle->lacp);
+ lacp_unref(bundle->lacp);
bundle->lacp = NULL;
}
bond_slave_register(bundle->bond, port, port->up.netdev);
}
} else {
- bond_destroy(bundle->bond);
+ bond_unref(bundle->bond);
bundle->bond = NULL;
}
if (list_is_empty(&bundle->ports)) {
bundle_destroy(bundle);
} else if (list_is_short(&bundle->ports)) {
- bond_destroy(bundle->bond);
+ bond_unref(bundle->bond);
bundle->bond = NULL;
}
}
} else {
VLOG_ERR_RL(&rl, "port %s: cannot obtain Ethernet address of iface "
"%s (%s)", port->bundle->name,
- netdev_get_name(port->up.netdev), strerror(error));
+ netdev_get_name(port->up.netdev), ovs_strerror(error));
}
}
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_WARN_RL(&rl, "bond %s: %d errors sending %d gratuitous learning "
"packets, last error was: %s",
- bundle->name, n_errors, n_packets, strerror(error));
+ bundle->name, n_errors, n_packets, ovs_strerror(error));
} else {
VLOG_DBG("bond %s: sent %d gratuitous learning packets",
bundle->name, n_packets);
if (ofport->may_enable != enable) {
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
-
- if (ofproto->has_bundle_action) {
- ofproto->backer->need_revalidate = REV_PORT_TOGGLED;
- }
+ ofproto->backer->need_revalidate = REV_PORT_TOGGLED;
}
ofport->may_enable = enable;
sset_find_and_delete(&ofproto->ghost_ports,
netdev_get_name(ofport->up.netdev));
ofproto->backer->need_revalidate = REV_RECONFIGURE;
- if (!ofport->tnl_port) {
+ if (!ofport->is_tunnel) {
error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
if (!error) {
/* The caller is going to close ofport->up.netdev. If this is a
struct dpif_backer *backer = miss->ofproto->backer;
uint32_t hash;
+ switch (flow_miss_model) {
+ case OFPROTO_HANDLE_MISS_AUTO:
+ break;
+ case OFPROTO_HANDLE_MISS_WITH_FACETS:
+ return true;
+ case OFPROTO_HANDLE_MISS_WITHOUT_FACETS:
+ return false;
+ }
+
if (!backer->governor) {
size_t n_subfacets;
subfacet->path = want_path;
ofpbuf_use_stack(&op->mask, &op->maskbuf, sizeof op->maskbuf);
- odp_flow_key_from_mask(&op->mask, &facet->xout.wc.masks,
- &miss->flow, UINT32_MAX);
+ if (enable_megaflows) {
+ odp_flow_key_from_mask(&op->mask, &facet->xout.wc.masks,
+ &miss->flow, UINT32_MAX);
+ }
op->xout_garbage = false;
op->dpif_op.type = DPIF_OP_FLOW_PUT;
if (error && !VLOG_DROP_WARN(&rl)) {
struct ds ds = DS_EMPTY_INITIALIZER;
odp_flow_key_format(drop_key->key, drop_key->key_len, &ds);
- VLOG_WARN("Failed to delete drop key (%s) (%s)", strerror(error),
- ds_cstr(&ds));
+ VLOG_WARN("Failed to delete drop key (%s) (%s)",
+ ovs_strerror(error), ds_cstr(&ds));
ds_destroy(&ds);
}
}
port = (tnl_port_should_receive(flow)
- ? ofport_dpif_cast(tnl_port_receive(flow))
+ ? tnl_port_receive(flow)
: odp_port_to_ofport(backer, flow->in_port.odp_port));
flow->in_port.ofp_port = port ? port->up.ofp_port : OFPP_NONE;
if (!port) {
facet->prev_used = facet->used;
in_port = get_ofp_port(ofproto, facet->flow.in_port.ofp_port);
- if (in_port && in_port->tnl_port) {
+ if (in_port && in_port->is_tunnel) {
netdev_vport_inc_rx(in_port->up.netdev, &stats);
}
}
ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
- odp_flow_key_from_mask(&mask, &facet->xout.wc.masks,
- &facet->flow, UINT32_MAX);
+ if (enable_megaflows) {
+ odp_flow_key_from_mask(&mask, &facet->xout.wc.masks,
+ &facet->flow, UINT32_MAX);
+ }
ret = dpif_flow_put(subfacet->backer->dpif, flags, subfacet->key,
subfacet->key_len, mask.data, mask.size,
if (error) {
VLOG_WARN_RL(&rl, "%s: failed to send packet on port %s (%s)",
ofproto->up.name, netdev_get_name(ofport->up.netdev),
- strerror(error));
+ ovs_strerror(error));
}
ofproto->stats.tx_packets++;
}
}
+tag_type
+calculate_flow_tag(struct ofproto_dpif *ofproto, const struct flow *flow,
+ uint8_t table_id, struct rule_dpif *rule)
+{
+ if (table_id > 0 && table_id < N_TABLES) {
+ struct table_dpif *table = &ofproto->tables[table_id];
+ if (table->other_table) {
+ return (rule && rule->tag
+ ? rule->tag
+ : rule_calculate_tag(flow, &table->other_table->mask,
+ table->basis));
+ }
+ }
+
+ return 0;
+}
\f
/* Optimized flow revalidation.
*
{
const struct dpif_backer *backer;
struct ofproto_dpif *ofproto;
- struct ofpbuf odp_key;
+ struct ofpbuf odp_key, odp_mask;
struct ofpbuf *packet;
struct ds result;
struct flow flow;
backer = NULL;
ds_init(&result);
ofpbuf_init(&odp_key, 0);
+ ofpbuf_init(&odp_mask, 0);
/* Handle "-generate" or a hex string as the last argument. */
if (!strcmp(argv[argc - 1], "-generate")) {
* bridge is specified. If function odp_flow_key_from_string()
* returns 0, the flow is a odp_flow. If function
* parse_ofp_exact_flow() returns 0, the flow is a br_flow. */
- if (!odp_flow_from_string(argv[argc - 1], NULL, &odp_key, NULL)) {
+ if (!odp_flow_from_string(argv[argc - 1], NULL, &odp_key, &odp_mask)) {
/* If the odp_flow is the second argument,
* the datapath name is the first argument. */
if (argc == 3) {
ds_destroy(&result);
ofpbuf_delete(packet);
ofpbuf_uninit(&odp_key);
+ ofpbuf_uninit(&odp_mask);
}
void
ds_destroy(&ds);
}
+/* Disable using the megaflows.
+ *
+ * This command is only needed for advanced debugging, so it's not
+ * documented in the man page. */
+static void
+ofproto_unixctl_dpif_disable_megaflows(struct unixctl_conn *conn,
+ int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED,
+ void *aux OVS_UNUSED)
+{
+ struct ofproto_dpif *ofproto;
+
+ enable_megaflows = false;
+
+ HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+ flush(&ofproto->up);
+ }
+
+ unixctl_command_reply(conn, "megaflows disabled");
+}
+
+/* Re-enable using megaflows.
+ *
+ * This command is only needed for advanced debugging, so it's not
+ * documented in the man page. */
+static void
+ofproto_unixctl_dpif_enable_megaflows(struct unixctl_conn *conn,
+ int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED,
+ void *aux OVS_UNUSED)
+{
+ struct ofproto_dpif *ofproto;
+
+ enable_megaflows = true;
+
+ HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+ flush(&ofproto->up);
+ }
+
+ unixctl_command_reply(conn, "megaflows enabled");
+}
+
static void
ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
int argc OVS_UNUSED, const char *argv[],
ofproto_unixctl_dpif_del_flows, NULL);
unixctl_command_register("dpif/dump-megaflows", "bridge", 1, 1,
ofproto_unixctl_dpif_dump_megaflows, NULL);
+ unixctl_command_register("dpif/disable-megaflows", "", 0, 0,
+ ofproto_unixctl_dpif_disable_megaflows, NULL);
+ unixctl_command_register("dpif/enable-megaflows", "", 0, 0,
+ ofproto_unixctl_dpif_enable_megaflows, NULL);
}
\f
/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
forward_bpdu_changed,
set_mac_table_config,
set_realdev,
+ NULL, /* meter_get_features */
+ NULL, /* meter_set */
+ NULL, /* meter_get */
+ NULL, /* meter_del */
};