uint16_t hard_timeout; /* In seconds from time of creation. */
long long int used; /* Last-used time (0 if never used). */
long long int created; /* Creation time. */
- uint64_t packet_count; /* Packets from *expired* subrules. */
- uint64_t byte_count; /* Bytes from *expired* subrules. */
+ uint64_t packet_count; /* Number of packets received. */
+ uint64_t byte_count; /* Number of bytes received. */
uint8_t tcp_flags; /* Bitwise-OR of all TCP flags seen. */
uint8_t ip_tos; /* Last-seen IP type-of-service. */
tag_type tags; /* Tags (set only by hooks). */
static bool rule_make_actions(struct ofproto *, struct rule *,
const struct ofpbuf *packet);
static void rule_install(struct ofproto *, struct rule *,
- struct odp_flow_stats *);
+ struct rule *displaced_rule);
static void rule_uninstall(struct ofproto *, struct rule *);
+static void rule_post_uninstall(struct ofproto *, struct rule *);
struct ofconn {
struct list node;
/* We might need to change the rules for arbitrary subrules. */
p->need_revalidate = true;
} else {
- struct odp_flow_stats stats;
-
rule_make_actions(p, rule, packet);
- rule_install(p, rule, &stats);
-
- if (displaced_rule && displaced_rule->super) {
- update_stats(displaced_rule->super, &stats);
- }
+ rule_install(p, rule, displaced_rule);
}
if (displaced_rule) {
rule_destroy(p, displaced_rule);
static void
rule_install(struct ofproto *p, struct rule *rule,
- struct odp_flow_stats *stats)
+ struct rule *displaced_rule)
{
assert(!rule->cr.wc.wildcards);
odp_flow.n_actions = rule->n_odp_actions;
if (!dpif_flow_add(&p->dpif, &odp_flow)) {
rule->installed = true;
- if (stats) {
- *stats = odp_flow.stats;
+ if (displaced_rule) {
+ update_stats(rule, &odp_flow.stats);
+ rule_post_uninstall(p, displaced_rule);
}
}
+ } else if (displaced_rule) {
+ rule_uninstall(p, displaced_rule);
}
}
if (rule->may_install) {
if (rule->installed) {
if (actions_changed) {
+ /* XXX should really do rule_post_uninstall() for the *old* set
+ * of actions, and distinguish the old stats from the new. */
dpif_flow_set_actions(&ofproto->dpif, &rule->cr.flow,
rule->odp_actions, rule->n_odp_actions);
}
assert(!rule->cr.wc.wildcards);
if (rule->installed) {
struct odp_flow odp_flow;
+
odp_flow.key = rule->cr.flow;
odp_flow.actions = NULL;
odp_flow.n_actions = 0;
if (!dpif_flow_del(&p->dpif, &odp_flow)) {
- update_stats(rule->super ? rule->super : rule, &odp_flow.stats);
+ update_stats(rule, &odp_flow.stats);
}
rule->installed = false;
- if (p->netflow) {
- struct ofexpired expired;
- expired.flow = rule->cr.flow;
- expired.packet_count = rule->packet_count;
- expired.byte_count = rule->byte_count;
- expired.used = rule->used;
- expired.created = rule->created;
- expired.tcp_flags = rule->tcp_flags;
- expired.ip_tos = rule->ip_tos;
- netflow_expire(p->netflow, &expired);
+ rule_post_uninstall(p, rule);
+ }
+}
+
+static void
+rule_post_uninstall(struct ofproto *ofproto, struct rule *rule)
+{
+ struct rule *super = rule->super;
+
+ if (ofproto->netflow) {
+ struct ofexpired expired;
+ expired.flow = rule->cr.flow;
+ expired.packet_count = rule->packet_count;
+ expired.byte_count = rule->byte_count;
+ expired.used = rule->used;
+ expired.created = rule->created;
+ expired.tcp_flags = rule->tcp_flags;
+ expired.ip_tos = rule->ip_tos;
+ netflow_expire(ofproto->netflow, &expired);
+ }
+ if (super) {
+ super->packet_count += rule->packet_count;
+ super->byte_count += rule->byte_count;
+ super->tcp_flags |= rule->tcp_flags;
+ if (rule->packet_count) {
+ super->ip_tos = rule->ip_tos;
}
}
+
+ /* Reset counters to prevent double counting if the rule ever gets
+ * reinstalled. */
+ rule->packet_count = 0;
+ rule->byte_count = 0;
+ rule->tcp_flags = 0;
+ rule->ip_tos = 0;
}
\f
static void
rule->packet_count += stats->n_packets;
rule->byte_count += stats->n_bytes;
rule->tcp_flags |= stats->tcp_flags;
- rule->ip_tos = stats->ip_tos;
+ if (stats->n_packets) {
+ rule->ip_tos = stats->ip_tos;
+ }
}
static int