struct ofport_dpif;
struct ofproto_dpif;
+struct flow_miss;
struct rule_dpif {
struct rule up;
* splinters can cause it to differ. This value should be removed when
* the VLAN splinters feature is no longer needed. */
ovs_be16 initial_tci; /* Initial VLAN TCI value. */
+
+ /* Datapath port the packet arrived on. This is needed to remove
+ * flows for ports that are no longer part of the bridge. Since the
+ * flow definition only has the OpenFlow port number and the port is
+ * no longer part of the bridge, we can't determine the datapath port
+ * number needed to delete the flow from the datapath. */
+ uint32_t odp_in_port;
};
#define SUBFACET_DESTROY_MAX_BATCH 50
-static struct subfacet *subfacet_create(struct facet *, enum odp_key_fitness,
- const struct nlattr *key,
- size_t key_len, ovs_be16 initial_tci,
+static struct subfacet *subfacet_create(struct facet *, struct flow_miss *miss,
long long int now);
static struct subfacet *subfacet_find(struct ofproto_dpif *,
const struct nlattr *key, size_t key_len,
return error;
}
\f
+static const char *
+port_open_type(const char *datapath_type, const char *port_type)
+{
+ return dpif_port_open_type(datapath_type, port_type);
+}
+
/* Type functions. */
+static struct ofproto_dpif *
+lookup_ofproto_dpif_by_port_name(const char *name)
+{
+ struct ofproto_dpif *ofproto;
+
+ HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+ if (sset_contains(&ofproto->ports, name)) {
+ return ofproto;
+ }
+ }
+
+ return NULL;
+}
+
static int
type_run(const char *type)
{
/* Check for port changes in the dpif. */
while ((error = dpif_port_poll(backer->dpif, &devname)) == 0) {
- struct ofproto_dpif *ofproto = NULL;
+ struct ofproto_dpif *ofproto;
struct dpif_port port;
/* Don't report on the datapath's device. */
if (!strcmp(devname, dpif_base_name(backer->dpif))) {
- continue;
- }
-
- HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node,
- &all_ofproto_dpifs) {
- if (sset_contains(&ofproto->ports, devname)) {
- break;
- }
+ goto next;
}
+ ofproto = lookup_ofproto_dpif_by_port_name(devname);
if (dpif_port_query_by_name(backer->dpif, devname, &port)) {
/* The port was removed. If we know the datapath,
* report it through poll_set(). If we don't, it may be
sset_add(&ofproto->port_poll_set, devname);
ofproto->port_poll_errno = 0;
}
- dpif_port_destroy(&port);
} else if (!ofproto) {
/* The port was added, but we don't know with which
* ofproto we should associate it. Delete it. */
dpif_port_del(backer->dpif, port.port_no);
}
+ dpif_port_destroy(&port);
+ next:
free(devname);
}
ofproto->port_poll_errno = 0;
SHASH_FOR_EACH_SAFE (node, next, &init_ofp_ports) {
- const struct iface_hint *iface_hint = node->data;
+ struct iface_hint *iface_hint = node->data;
if (!strcmp(iface_hint->br_name, ofproto->up.name)) {
/* Check if the datapath already has this port. */
free(iface_hint->br_name);
free(iface_hint->br_type);
+ free(iface_hint);
shash_delete(&init_ofp_ports, node);
}
}
{
struct ofport_dpif *port = ofport_dpif_cast(port_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
- struct dpif_port dpif_port;
+ const char *devname = netdev_get_name(port->up.netdev);
- if (!dpif_port_query_by_number(ofproto->backer->dpif,
- port->odp_port, &dpif_port)) {
+ if (dpif_port_exists(ofproto->backer->dpif, devname)) {
/* The underlying device is still there, so delete it. This
* happens when the ofproto is being destroyed, since the caller
* assumes that removal of attached ports will happen as part of
* destruction. */
dpif_port_del(ofproto->backer->dpif, port->odp_port);
- dpif_port_destroy(&dpif_port);
}
- sset_find_and_delete(&ofproto->ports, netdev_get_name(port->up.netdev));
+ sset_find_and_delete(&ofproto->ports, devname);
hmap_remove(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node);
ofproto->need_revalidate = REV_RECONFIGURE;
bundle_remove(port_);
}
static void
-set_mac_idle_time(struct ofproto *ofproto_, unsigned int idle_time)
+set_mac_table_config(struct ofproto *ofproto_, unsigned int idle_time,
+ size_t max_entries)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
mac_learning_set_idle_time(ofproto->ml, idle_time);
+ mac_learning_set_max_entries(ofproto->ml, max_entries);
}
\f
/* Ports. */
ovs_be16 initial_tci;
struct list packets;
enum dpif_upcall_type upcall_type;
+ uint32_t odp_in_port;
};
struct flow_miss_op {
struct subfacet *subfacet;
struct ofpbuf *packet;
- subfacet = subfacet_create(facet,
- miss->key_fitness, miss->key, miss->key_len,
- miss->initial_tci, now);
+ subfacet = subfacet_create(facet, miss, now);
LIST_FOR_EACH (packet, list_node, &miss->packets) {
struct flow_miss_op *op = &ops[*n_ops];
enum odp_key_fitness fitness;
struct ofproto_dpif *ofproto;
struct ofport_dpif *port;
+ uint32_t odp_in_port;
struct flow flow;
uint32_t hash;
continue;
}
ofproto = ofproto_dpif_cast(port->up.ofproto);
+ odp_in_port = flow.in_port;
flow.in_port = port->up.ofp_port;
/* Obtain metadata and check userspace/kernel agreement on flow match,
if (miss->key_fitness == ODP_FIT_ERROR) {
continue;
}
- flow_extract(upcall->packet, flow.skb_priority,
+ flow_extract(upcall->packet, flow.skb_priority, flow.skb_mark,
&flow.tunnel, flow.in_port, &miss->flow);
/* Add other packets to a to-do list. */
miss->key = upcall->key;
miss->key_len = upcall->key_len;
miss->upcall_type = upcall->type;
+ miss->odp_in_port = odp_in_port;
list_init(&miss->packets);
n_misses++;
if (!port) {
/* This flow is for a port for which we couldn't associate an
* ofproto. This can happen if a port is removed while
- * traffic is being received. Print a rate-limited message
- * in case it happens frequently. */
- VLOG_INFO_RL(&rl,
- "stats update for flow with unassociated port %"PRIu32,
- flow.in_port);
+ * traffic is being received. Ignore this flow, since it
+ * will get timed out. */
continue;
}
}
/* Searches 'facet' (within 'ofproto') for a subfacet with the specified
- * 'key_fitness', 'key', and 'key_len'. Returns the existing subfacet if
- * there is one, otherwise creates and returns a new subfacet.
+ * 'key_fitness', 'key', and 'key_len' members in 'miss'. Returns the
+ * existing subfacet if there is one, otherwise creates and returns a
+ * new subfacet.
*
* If the returned subfacet is new, then subfacet->actions will be NULL, in
* which case the caller must populate the actions with
* subfacet_make_actions(). */
static struct subfacet *
-subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness,
- const struct nlattr *key, size_t key_len,
- ovs_be16 initial_tci, long long int now)
+subfacet_create(struct facet *facet, struct flow_miss *miss,
+ long long int now)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
- uint32_t key_hash = odp_flow_key_hash(key, key_len);
+ enum odp_key_fitness key_fitness = miss->key_fitness;
+ const struct nlattr *key = miss->key;
+ size_t key_len = miss->key_len;
+ uint32_t key_hash;
struct subfacet *subfacet;
+ key_hash = odp_flow_key_hash(key, key_len);
+
if (list_is_empty(&facet->subfacets)) {
subfacet = &facet->one_subfacet;
} else {
? SLOW_MATCH
: 0);
subfacet->path = SF_NOT_INSTALLED;
- subfacet->initial_tci = initial_tci;
+ subfacet->initial_tci = miss->initial_tci;
+ subfacet->odp_in_port = miss->odp_in_port;
return subfacet;
}
{
if (!subfacet->key) {
- struct ofproto_dpif *ofproto;
struct flow *flow = &subfacet->facet->flow;
ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
- ofproto = ofproto_dpif_cast(subfacet->facet->rule->up.ofproto);
- odp_flow_key_from_flow(key, flow,
- ofp_port_to_odp_port(ofproto, flow->in_port));
+ odp_flow_key_from_flow(key, flow, subfacet->odp_in_port);
} else {
ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
}
struct flow flow;
int error;
- flow_extract(packet, 0, NULL, 0, &flow);
+ flow_extract(packet, 0, 0, NULL, OFPP_LOCAL, &flow);
odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
flow.vlan_tci);
if (odp_port != ofport->odp_port) {
uint32_t odp_port = ofp_port_to_odp_port(ctx->ofproto, ofp_port);
ovs_be16 flow_vlan_tci = ctx->flow.vlan_tci;
uint8_t flow_nw_tos = ctx->flow.nw_tos;
- uint16_t out_port;
-
- if (ofport) {
- struct priority_to_dscp *pdscp;
+ struct priority_to_dscp *pdscp;
+ uint32_t out_port;
- if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD) {
- xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
- return;
- } else if (check_stp && !stp_forward_in_state(ofport->stp_state)) {
- xlate_report(ctx, "STP not in forwarding state, skipping output");
- return;
- }
+ if (!ofport) {
+ xlate_report(ctx, "Nonexistent output port");
+ return;
+ } else if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD) {
+ xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
+ return;
+ } else if (check_stp && !stp_forward_in_state(ofport->stp_state)) {
+ xlate_report(ctx, "STP not in forwarding state, skipping output");
+ return;
+ }
- pdscp = get_priority(ofport, ctx->flow.skb_priority);
- if (pdscp) {
- ctx->flow.nw_tos &= ~IP_DSCP_MASK;
- ctx->flow.nw_tos |= pdscp->dscp;
- }
- } else {
- /* We may not have an ofport record for this port, but it doesn't hurt
- * to allow forwarding to it anyhow. Maybe such a port will appear
- * later and we're pre-populating the flow table. */
+ pdscp = get_priority(ofport, ctx->flow.skb_priority);
+ if (pdscp) {
+ ctx->flow.nw_tos &= ~IP_DSCP_MASK;
+ ctx->flow.nw_tos |= pdscp->dscp;
}
out_port = vsp_realdev_to_vlandev(ctx->ofproto, odp_port,
}
if (rule == NULL && may_packet_in) {
- /* TODO:XXX
+ /* XXX
* check if table configuration flags
* OFPTC_TABLE_MISS_CONTROLLER, default.
* OFPTC_TABLE_MISS_CONTINUE,
break;
case OFPACT_PUSH_VLAN:
- /* TODO:XXX 802.1AD(QinQ) */
+ /* XXX 802.1AD(QinQ) */
ctx->flow.vlan_tci = htons(VLAN_CFI);
break;
break;
case OFPACT_CLEAR_ACTIONS:
- /* TODO:XXX
+ /* XXX
* Nothing to do because writa-actions is not supported for now.
* When writa-actions is supported, clear-actions also must
* be supported at the same time.
break;
case OFPACT_GOTO_TABLE: {
- /* TODO:XXX remove recursion */
+ /* XXX remove recursion */
/* It is assumed that goto-table is last action */
struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);
assert(ctx->table_id < ogt->table_id);
{
ctx->ofproto = ofproto;
ctx->flow = *flow;
+ memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
ctx->base_flow = ctx->flow;
- memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
ctx->base_flow.vlan_tci = initial_tci;
ctx->rule = rule;
ctx->packet = packet;
packet = ofpbuf_new(0);
flow_compose(packet, &flow);
}
- } else if (argc == 6) {
- /* ofproto/trace dpname priority tun_id in_port packet */
+ } else if (argc == 7) {
+ /* ofproto/trace dpname priority tun_id in_port mark packet */
const char *priority_s = argv[2];
const char *tun_id_s = argv[3];
const char *in_port_s = argv[4];
- const char *packet_s = argv[5];
+ const char *mark_s = argv[5];
+ const char *packet_s = argv[6];
uint32_t in_port = atoi(in_port_s);
ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
uint32_t priority = atoi(priority_s);
+ uint32_t mark = atoi(mark_s);
const char *msg;
msg = eth_from_hex(packet_s, &packet);
ds_put_cstr(&result, s);
free(s);
- flow_extract(packet, priority, NULL, in_port, &flow);
+ flow_extract(packet, priority, mark, NULL, in_port, &flow);
flow.tunnel.tun_id = tun_id;
initial_tci = flow.vlan_tci;
} else {
unixctl_command_register(
"ofproto/trace",
- "bridge {tun_id in_port packet | odp_flow [-generate]}",
- 2, 5, ofproto_unixctl_trace, NULL);
+ "bridge {priority tun_id in_port mark packet | odp_flow [-generate]}",
+ 2, 6, ofproto_unixctl_trace, NULL);
unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
ofproto_unixctl_fdb_flush, NULL);
unixctl_command_register("fdb/show", "bridge", 1, 1,
enumerate_types,
enumerate_names,
del,
+ port_open_type,
type_run,
type_run_fast,
type_wait,
set_flood_vlans,
is_mirror_output_bundle,
forward_bpdu_changed,
- set_mac_idle_time,
+ set_mac_table_config,
set_realdev,
};