static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes);
static struct rule_dpif *rule_dpif_cast(const struct rule *);
+struct group_dpif {
+ struct ofgroup up;
+
+ /* These statistics:
+ *
+ * - Do include packets and bytes from facets that have been deleted or
+ * whose own statistics have been folded into the rule.
+ *
+ * - Do include packets and bytes sent "by hand" that were accounted to
+ * the rule without any facet being involved (this is a rare corner
+ * case in rule_execute()).
+ *
+ * - Do not include packet or bytes that can be obtained from any facet's
+ * packet_count or byte_count member or that can be obtained from the
+ * datapath by, e.g., dpif_flow_get() for any subfacet.
+ */
+ struct ovs_mutex stats_mutex;
+ uint64_t packet_count OVS_GUARDED; /* Number of packets received. */
+ uint64_t byte_count OVS_GUARDED; /* Number of bytes received. */
+ struct bucket_counter *bucket_stats OVS_GUARDED; /* Bucket statistics. */
+};
+
struct ofbundle {
struct hmap_node hmap_node; /* In struct ofproto's "bundles" hmap. */
struct ofproto_dpif *ofproto; /* Owning ofproto. */
/* Accounting. */
uint64_t accounted_bytes; /* Bytes processed by facet_account(). */
struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */
- uint8_t tcp_flags; /* TCP flags seen for this 'rule'. */
+ uint16_t tcp_flags; /* TCP flags seen for this 'rule'. */
struct xlate_out xout;
* Takes ownership of 'pin' and pin->packet. */
void
ofproto_dpif_send_packet_in(struct ofproto_dpif *ofproto,
- struct ofputil_packet_in *pin)
+ struct ofproto_packet_in *pin)
{
if (!guarded_list_push_back(&ofproto->pins, &pin->list_node, 1024)) {
COVERAGE_INC(packet_in_overflow);
- free(CONST_CAST(void *, pin->packet));
+ free(CONST_CAST(void *, pin->up.packet));
free(pin);
}
}
ofport->up.netdev, ofport->cfm,
ofport->bfd, ofport->peer, stp_port,
ofport->qdscp, ofport->n_qdscp,
- ofport->up.pp.config, ofport->is_tunnel,
- ofport->may_enable);
+ ofport->up.pp.config, ofport->up.pp.state,
+ ofport->is_tunnel, ofport->may_enable);
}
ovs_rwlock_unlock(&xlate_rwlock);
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct shash_node *node, *next;
- uint32_t max_ports;
int error;
error = open_dpif_backer(ofproto->up.type, &ofproto->backer);
return error;
}
- max_ports = dpif_get_max_ports(ofproto->backer->dpif);
- ofproto_init_max_ports(ofproto_, MIN(max_ports, ofp_to_u16(OFPP_MAX)));
-
ofproto->netflow = NULL;
ofproto->sflow = NULL;
ofproto->ipfix = NULL;
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct rule_dpif *rule, *next_rule;
- struct ofputil_packet_in *pin, *next_pin;
+ struct ofproto_packet_in *pin, *next_pin;
struct facet *facet, *next_facet;
struct cls_cursor cursor;
struct oftable *table;
guarded_list_pop_all(&ofproto->pins, &pins);
LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
list_remove(&pin->list_node);
- free(CONST_CAST(void *, pin->packet));
+ free(CONST_CAST(void *, pin->up.packet));
free(pin);
}
guarded_list_destroy(&ofproto->pins);
run_fast(struct ofproto *ofproto_)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- struct ofputil_packet_in *pin, *next_pin;
+ struct ofproto_packet_in *pin, *next_pin;
struct list pins;
/* Do not perform any periodic activity required by 'ofproto' while
LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
connmgr_send_packet_in(ofproto->up.connmgr, pin);
list_remove(&pin->list_node);
- free(CONST_CAST(void *, pin->packet));
+ free(CONST_CAST(void *, pin->up.packet));
free(pin);
}
- ofproto_dpif_monitor_run_fast();
return 0;
}
dpif_ipfix_run(ofproto->ipfix);
}
- ofproto_dpif_monitor_run_fast();
- ofproto_dpif_monitor_run();
-
HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
port_run(ofport);
}
if (time_msec() >= ofproto->consistency_rl
&& !classifier_is_empty(&ofproto->facets)
&& !ofproto->backer->need_revalidate) {
- struct cls_table *table;
+ struct cls_subtable *table;
struct cls_rule *cr;
struct facet *facet;
ofproto->consistency_rl = time_msec() + 250;
- table = CONTAINER_OF(hmap_random_node(&ofproto->facets.tables),
- struct cls_table, hmap_node);
+ table = CONTAINER_OF(hmap_random_node(&ofproto->facets.subtables),
+ struct cls_subtable, hmap_node);
cr = CONTAINER_OF(hmap_random_node(&table->rules), struct cls_rule,
hmap_node);
facet = CONTAINER_OF(cr, struct facet, cr);
if (ofproto->ipfix) {
dpif_ipfix_wait(ofproto->ipfix);
}
- ofproto_dpif_monitor_wait();
HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) {
bundle_wait(bundle);
}
if (ofport->cfm) {
status->faults = cfm_get_fault(ofport->cfm);
+ status->flap_count = cfm_get_flap_count(ofport->cfm);
status->remote_opstate = cfm_get_opup(ofport->cfm);
status->health = cfm_get_health(ofport->cfm);
cfm_get_remote_mpids(ofport->cfm, &status->rmps, &status->n_rmps);
/* Executes, within 'ofproto', the actions in 'rule' or 'ofpacts' on 'packet'.
* 'flow' must reflect the data in 'packet'. */
-static int
-execute_actions(struct ofproto *ofproto_, const struct flow *flow,
- struct rule_dpif *rule,
- const struct ofpact *ofpacts, size_t ofpacts_len,
- struct ofpbuf *packet)
+int
+ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
+ const struct flow *flow,
+ struct rule_dpif *rule,
+ const struct ofpact *ofpacts, size_t ofpacts_len,
+ struct ofpbuf *packet)
{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct odputil_keybuf keybuf;
struct dpif_flow_stats stats;
struct xlate_out xout;
}
bool
-rule_dpif_fail_open(const struct rule_dpif *rule)
+rule_dpif_is_fail_open(const struct rule_dpif *rule)
{
- return rule->up.cr.priority == FAIL_OPEN_PRIORITY;
+ return is_fail_open_rule(&rule->up);
+}
+
+bool
+rule_dpif_is_table_miss(const struct rule_dpif *rule)
+{
+ return rule_is_table_miss(&rule->up);
}
ovs_be64
cls_rule = classifier_lookup(cls, &ofpc_normal_flow, wc);
} else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
cls_rule = &ofproto->drop_frags_rule->up.cr;
- if (wc) {
- flow_wildcards_init_exact(wc);
- }
+ /* Frag mask in wc already set above. */
} else {
cls_rule = classifier_lookup(cls, flow, wc);
}
rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
struct ofpbuf *packet)
{
- execute_actions(rule->up.ofproto, flow, rule, NULL, 0, packet);
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+
+ ofproto_dpif_execute_actions(ofproto, flow, rule, NULL, 0, packet);
}
static enum ofperr
complete_operation(rule);
}
+
+static struct group_dpif *group_dpif_cast(const struct ofgroup *group)
+{
+ return group ? CONTAINER_OF(group, struct group_dpif, up) : NULL;
+}
+
+static struct ofgroup *
+group_alloc(void)
+{
+ struct group_dpif *group = xzalloc(sizeof *group);
+ return &group->up;
+}
+
+static void
+group_dealloc(struct ofgroup *group_)
+{
+ struct group_dpif *group = group_dpif_cast(group_);
+ free(group);
+}
+
+static void
+group_construct_stats(struct group_dpif *group)
+ OVS_REQUIRES(group->stats_mutex)
+{
+ group->packet_count = 0;
+ group->byte_count = 0;
+ if (!group->bucket_stats) {
+ group->bucket_stats = xcalloc(group->up.n_buckets,
+ sizeof *group->bucket_stats);
+ } else {
+ memset(group->bucket_stats, 0, group->up.n_buckets *
+ sizeof *group->bucket_stats);
+ }
+}
+
+static enum ofperr
+group_construct(struct ofgroup *group_)
+{
+ struct group_dpif *group = group_dpif_cast(group_);
+ ovs_mutex_init(&group->stats_mutex);
+ ovs_mutex_lock(&group->stats_mutex);
+ group_construct_stats(group);
+ ovs_mutex_unlock(&group->stats_mutex);
+ return 0;
+}
+
+static void
+group_destruct__(struct group_dpif *group)
+ OVS_REQUIRES(group->stats_mutex)
+{
+ free(group->bucket_stats);
+ group->bucket_stats = NULL;
+}
+
+static void
+group_destruct(struct ofgroup *group_)
+{
+ struct group_dpif *group = group_dpif_cast(group_);
+ ovs_mutex_lock(&group->stats_mutex);
+ group_destruct__(group);
+ ovs_mutex_unlock(&group->stats_mutex);
+ ovs_mutex_destroy(&group->stats_mutex);
+}
+
+static enum ofperr
+group_modify(struct ofgroup *group_, struct ofgroup *victim_)
+{
+ struct group_dpif *group = group_dpif_cast(group_);
+ struct group_dpif *victim = group_dpif_cast(victim_);
+
+ ovs_mutex_lock(&group->stats_mutex);
+ if (victim->up.n_buckets < group->up.n_buckets) {
+ group_destruct__(group);
+ }
+ group_construct_stats(group);
+ ovs_mutex_unlock(&group->stats_mutex);
+
+ return 0;
+}
+
+static enum ofperr
+group_get_stats(const struct ofgroup *group_, struct ofputil_group_stats *ogs)
+{
+ struct group_dpif *group = group_dpif_cast(group_);
+
+ /* Start from historical data for 'group' itself that are no longer tracked
+ * in facets. This counts, for example, facets that have expired. */
+ ovs_mutex_lock(&group->stats_mutex);
+ ogs->packet_count = group->packet_count;
+ ogs->byte_count = group->byte_count;
+ memcpy(ogs->bucket_stats, group->bucket_stats,
+ group->up.n_buckets * sizeof *group->bucket_stats);
+ ovs_mutex_unlock(&group->stats_mutex);
+
+ return 0;
+}
+
+bool
+group_dpif_lookup(struct ofproto_dpif *ofproto, uint32_t group_id,
+ struct group_dpif **group)
+ OVS_TRY_RDLOCK(true, (*group)->up.rwlock)
+{
+ struct ofgroup *ofgroup;
+ bool found;
+
+ *group = NULL;
+ found = ofproto_group_lookup(&ofproto->up, group_id, &ofgroup);
+ *group = found ? group_dpif_cast(ofgroup) : NULL;
+
+ return found;
+}
+
+void
+group_dpif_release(struct group_dpif *group)
+ OVS_RELEASES(group->up.rwlock)
+{
+ ofproto_group_release(&group->up);
+}
+
+void
+group_dpif_get_buckets(const struct group_dpif *group,
+ const struct list **buckets)
+{
+ *buckets = &group->up.buckets;
+}
+
+enum ofp11_group_type
+group_dpif_get_type(const struct group_dpif *group)
+{
+ return group->up.type;
+}
\f
/* Sends 'packet' out 'ofport'.
* May modify 'packet'.
}
static enum ofperr
-packet_out(struct ofproto *ofproto, struct ofpbuf *packet,
+packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
const struct flow *flow,
const struct ofpact *ofpacts, size_t ofpacts_len)
{
- execute_actions(ofproto, flow, NULL, ofpacts, ofpacts_len, packet);
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+
+ ofproto_dpif_execute_actions(ofproto, flow, NULL, ofpacts,
+ ofpacts_len, packet);
return 0;
}
\f
actions = rule_dpif_get_actions(rule);
ds_put_char_multiple(result, '\t', level);
- ds_put_cstr(result, "OpenFlow ");
+ ds_put_cstr(result, "OpenFlow actions=");
ofpacts_format(actions->ofpacts, actions->ofpacts_len, result);
ds_put_char(result, '\n');
ds_put_char(result, '\n');
}
-static void
-ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
- void *aux OVS_UNUSED)
+/* Parses the 'argc' elements of 'argv', ignoring argv[0]. The following
+ * forms are supported:
+ *
+ * - [dpname] odp_flow [-generate | packet]
+ * - bridge br_flow [-generate | packet]
+ *
+ * On success, initializes '*ofprotop' and 'flow' and returns NULL. On failure
+ * returns a nonnull error message. */
+static const char *
+parse_flow_and_packet(int argc, const char *argv[],
+ struct ofproto_dpif **ofprotop, struct flow *flow,
+ struct ofpbuf **packetp)
{
const struct dpif_backer *backer = NULL;
- struct ofproto_dpif *ofproto;
- struct ofpbuf odp_key, odp_mask;
+ const char *error = NULL;
+ struct simap port_names = SIMAP_INITIALIZER(&port_names);
struct ofpbuf *packet;
- struct ds result;
- struct flow flow;
- struct simap port_names;
- char *s;
+ struct ofpbuf odp_key;
+ struct ofpbuf odp_mask;
- packet = NULL;
- backer = NULL;
- ds_init(&result);
ofpbuf_init(&odp_key, 0);
ofpbuf_init(&odp_mask, 0);
- simap_init(&port_names);
/* Handle "-generate" or a hex string as the last argument. */
if (!strcmp(argv[argc - 1], "-generate")) {
packet = ofpbuf_new(0);
argc--;
} else {
- const char *error = eth_from_hex(argv[argc - 1], &packet);
+ error = eth_from_hex(argv[argc - 1], &packet);
if (!error) {
argc--;
} else if (argc == 4) {
/* The 3-argument form must end in "-generate' or a hex string. */
- unixctl_command_reply_error(conn, error);
goto exit;
}
}
dp_type = argv[1];
}
backer = shash_find_data(&all_dpif_backers, dp_type);
- } else {
+ } else if (argc == 2) {
struct shash_node *node;
if (shash_count(&all_dpif_backers) == 1) {
node = shash_first(&all_dpif_backers);
backer = node->data;
}
+ } else {
+ error = "Syntax error";
+ goto exit;
}
if (backer && backer->dpif) {
struct dpif_port dpif_port;
* 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], &port_names, &odp_key, &odp_mask)) {
+ if (!odp_flow_from_string(argv[argc - 1], &port_names,
+ &odp_key, &odp_mask)) {
if (!backer) {
- unixctl_command_reply_error(conn, "Cannot find the datapath");
+ error = "Cannot find the datapath";
goto exit;
}
- if (xlate_receive(backer, NULL, odp_key.data, odp_key.size, &flow,
- NULL, &ofproto, NULL)) {
- unixctl_command_reply_error(conn, "Invalid datapath flow");
+ if (xlate_receive(backer, NULL, odp_key.data, odp_key.size, flow,
+ NULL, ofprotop, NULL)) {
+ error = "Invalid datapath flow";
goto exit;
}
- ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
- } else if (!parse_ofp_exact_flow(&flow, argv[argc - 1])) {
+ } else if (!parse_ofp_exact_flow(flow, NULL, argv[argc - 1], NULL)) {
if (argc != 3) {
- unixctl_command_reply_error(conn, "Must specify bridge name");
+ error = "Must specify bridge name";
goto exit;
}
- ofproto = ofproto_dpif_lookup(argv[1]);
- if (!ofproto) {
- unixctl_command_reply_error(conn, "Unknown bridge name");
+ *ofprotop = ofproto_dpif_lookup(argv[1]);
+ if (!*ofprotop) {
+ error = "Unknown bridge name";
goto exit;
}
} else {
- unixctl_command_reply_error(conn, "Bad flow syntax");
+ error = "Bad flow syntax";
goto exit;
}
/* Generate a packet, if requested. */
if (packet) {
if (!packet->size) {
- flow_compose(packet, &flow);
+ flow_compose(packet, flow);
} else {
- union flow_in_port in_port_;
-
- in_port_ = flow.in_port;
- ds_put_cstr(&result, "Packet: ");
- s = ofp_packet_to_string(packet->data, packet->size);
- ds_put_cstr(&result, s);
- free(s);
+ union flow_in_port in_port = flow->in_port;
/* Use the metadata from the flow and the packet argument
* to reconstruct the flow. */
- flow_extract(packet, flow.skb_priority, flow.pkt_mark, NULL,
- &in_port_, &flow);
+ flow_extract(packet, flow->skb_priority, flow->pkt_mark, NULL,
+ &in_port, flow);
}
}
- ofproto_trace(ofproto, &flow, packet, &result);
- unixctl_command_reply(conn, ds_cstr(&result));
+ error = NULL;
exit:
- ds_destroy(&result);
- ofpbuf_delete(packet);
+ if (error) {
+ ofpbuf_delete(packet);
+ packet = NULL;
+ }
+ *packetp = packet;
ofpbuf_uninit(&odp_key);
ofpbuf_uninit(&odp_mask);
simap_destroy(&port_names);
+ return error;
+}
+
+static void
+ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
+ void *aux OVS_UNUSED)
+{
+ struct ofproto_dpif *ofproto;
+ struct ofpbuf *packet;
+ const char *error;
+ struct flow flow;
+
+ error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
+ if (!error) {
+ struct ds result;
+
+ ds_init(&result);
+ ofproto_trace(ofproto, &flow, packet, &result);
+ unixctl_command_reply(conn, ds_cstr(&result));
+ ds_destroy(&result);
+ ofpbuf_delete(packet);
+ } else {
+ unixctl_command_reply_error(conn, error);
+ }
}
static void
struct ofpbuf odp_actions;
struct trace_ctx trace;
struct match match;
- uint8_t tcp_flags;
+ uint16_t tcp_flags;
tcp_flags = packet ? packet_get_tcp_flags(packet, flow) : 0;
trace.result = ds;
NULL, /* meter_set */
NULL, /* meter_get */
NULL, /* meter_del */
- NULL, /* group_alloc */
- NULL, /* group_construct */
- NULL, /* group_destruct */
- NULL, /* group_dealloc */
- NULL, /* group_modify */
- NULL, /* group_get_stats */
+ group_alloc, /* group_alloc */
+ group_construct, /* group_construct */
+ group_destruct, /* group_destruct */
+ group_dealloc, /* group_dealloc */
+ group_modify, /* group_modify */
+ group_get_stats, /* group_get_stats */
};