[ovs-dev] [PATCH 1/2] ofproto: Resubmit packet and byte count statistics.

Ethan Jackson ethan at nicira.com
Tue Oct 12 22:34:05 UTC 2010


This patch maintains packet and byte count statistics when
resubmits are involved.  For a particular rule A, it builds a tree
rooted at A of all rules which resubmit into it.  Thus when
statistics are queried for A, it can incorporate its "children"
statistics as well.
---
 ofproto/ofproto.c |  132 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 115 insertions(+), 17 deletions(-)

diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index e25ce28..401a11a 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -80,12 +80,6 @@ struct ofport {
 static void ofport_free(struct ofport *);
 static void hton_ofp_phy_port(struct ofp_phy_port *);
 
-static int xlate_actions(const union ofp_action *in, size_t n_in,
-                         const struct flow *, struct ofproto *,
-                         const struct ofpbuf *packet,
-                         struct odp_actions *out, tag_type *tags,
-                         bool *may_set_up_flow, uint16_t *nf_output_iface);
-
 struct rule {
     struct cls_rule cr;
 
@@ -131,8 +125,27 @@ struct rule {
                                  * be reassessed for every packet. */
     int n_odp_actions;
     union odp_action *odp_actions;
+
+    /* Resubmit Tree.
+     *
+     * Rules maintain a "resubmit tree" used to keep track of packet and byte
+     * count statistics.  Suppose rule_a resubmits into rule_b.  In this case,
+     * rule_b will maintain the rule_a rs_node in its rs_children list.  In
+     * addition rule_a will store rule_b in its rs_parent. */
+    struct rule *rs_parent;
+    struct list rs_node;
+    struct list rs_children;
 };
 
+static int xlate_actions(const union ofp_action *in, size_t n_in,
+                         struct rule *, const struct flow *,
+                         struct ofproto *, const struct ofpbuf *packet,
+                         struct odp_actions *out, tag_type *tags,
+                         bool *may_set_up_flow, uint16_t *nf_output_iface);
+
+static void query_stats(struct ofproto *, struct rule *,
+                        uint64_t *packet_countp, uint64_t *byte_countp);
+
 static inline bool
 rule_is_hidden(const struct rule *rule)
 {
@@ -170,6 +183,9 @@ static void rule_uninstall(struct ofproto *, struct rule *);
 static void rule_post_uninstall(struct ofproto *, struct rule *);
 static void send_flow_removed(struct ofproto *p, struct rule *rule,
                               long long int now, uint8_t reason);
+static void add_resubmit_rule(struct ofproto *,
+                              struct rule *parent, struct rule *);
+static void del_resubmit_rule(struct ofproto *, struct rule *);
 
 /* ofproto supports two kinds of OpenFlow connections:
  *
@@ -1285,7 +1301,8 @@ ofproto_send_packet(struct ofproto *p, const struct flow *flow,
     struct odp_actions odp_actions;
     int error;
 
-    error = xlate_actions(actions, n_actions, flow, p, packet, &odp_actions,
+    error = xlate_actions(actions, n_actions, NULL,
+                          flow, p, packet, &odp_actions,
                           NULL, NULL, NULL);
     if (error) {
         return error;
@@ -1854,6 +1871,9 @@ rule_create(struct ofproto *ofproto, struct rule *super,
         rule->n_actions = n_actions;
         rule->actions = xmemdup(actions, n_actions * sizeof *actions);
     }
+
+    list_init(&rule->rs_node);
+    list_init(&rule->rs_children);
     netflow_flow_clear(&rule->nf_flow);
     netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->created);
 
@@ -1885,6 +1905,8 @@ rule_free(struct rule *rule)
 static void
 rule_destroy(struct ofproto *ofproto, struct rule *rule)
 {
+    del_resubmit_rule(ofproto, rule);
+
     if (!rule->super) {
         struct rule *subrule, *next;
         LIST_FOR_EACH_SAFE (subrule, next, list, &rule->list) {
@@ -1896,6 +1918,61 @@ rule_destroy(struct ofproto *ofproto, struct rule *rule)
     rule_free(rule);
 }
 
+/* Deletes 'rule' from the resubmit tree it may or may not be in.  This involves
+ * removing 'rule' from it's parent, updating it's parent's count statistics,
+ * and updating it's children */
+static void
+del_resubmit_rule(struct ofproto *ofproto, struct rule *rule)
+{
+
+    if (rule->rs_parent) {
+        uint64_t packet_count, byte_count;
+
+        query_stats(ofproto, rule, &packet_count, &byte_count);
+
+        assert(!list_is_empty(&rule->rs_node));
+        list_remove(&rule->rs_node);
+        list_init(&rule->rs_node);
+
+        rule->rs_parent->packet_count += packet_count;
+        rule->rs_parent->byte_count   += byte_count;
+        rule->rs_parent                = NULL;
+    }
+
+    if (!list_is_empty(&rule->rs_children)) {
+        struct rule *child, *child_next;
+        ofproto->need_revalidate = true;
+
+        LIST_FOR_EACH_SAFE(child, child_next, rs_node, &rule->rs_children) {
+            child->rs_parent = NULL;
+            list_remove(&child->rs_node);
+            list_init(&child->rs_node);
+        }
+    }
+}
+
+/* Add 'rule' to the resubmit tree of 'parent'. */
+static void
+add_resubmit_rule(struct ofproto *ofproto,
+                  struct rule *parent, struct rule *rule)
+{
+    uint64_t packet_count, byte_count;
+
+    if (rule->rs_parent == parent) {
+        return;
+    }
+
+    assert(parent != rule);
+
+    del_resubmit_rule(ofproto, rule);
+    query_stats(ofproto, rule, &packet_count, &byte_count);
+    parent->packet_count -= packet_count;
+    parent->byte_count   -= byte_count;
+
+    rule->rs_parent = parent;
+    list_push_back(&parent->rs_children, &rule->rs_node);
+}
+
 static bool
 rule_has_out_port(const struct rule *rule, uint16_t out_port)
 {
@@ -1984,7 +2061,8 @@ rule_execute(struct ofproto *ofproto, struct rule *rule,
      * scenario. */
     if (rule->cr.wc.wildcards || !flow_equal(flow, &rule->cr.flow)) {
         struct rule *super = rule->super ? rule->super : rule;
-        if (xlate_actions(super->actions, super->n_actions, flow, ofproto,
+        if (xlate_actions(super->actions, super->n_actions,
+                          rule, flow, ofproto,
                           packet, &a, NULL, 0, NULL)) {
             ofpbuf_delete(packet);
             return;
@@ -2075,6 +2153,8 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule,
 static void
 rule_remove(struct ofproto *ofproto, struct rule *rule)
 {
+    del_resubmit_rule(ofproto, rule);
+
     if (rule->cr.wc.wildcards) {
         COVERAGE_INC(ofproto_del_wc_flow);
         ofproto->need_revalidate = true;
@@ -2090,7 +2170,7 @@ static bool
 rule_make_actions(struct ofproto *p, struct rule *rule,
                   const struct ofpbuf *packet)
 {
-    const struct rule *super;
+    struct rule *super;
     struct odp_actions a;
     size_t actions_len;
 
@@ -2098,7 +2178,7 @@ rule_make_actions(struct ofproto *p, struct rule *rule,
 
     super = rule->super ? rule->super : rule;
     rule->tags = 0;
-    xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p,
+    xlate_actions(super->actions, super->n_actions, rule, &rule->cr.flow, p,
                   packet, &a, &rule->tags, &rule->may_install,
                   &rule->nf_flow.output_iface);
 
@@ -2439,6 +2519,7 @@ add_controller_action(struct odp_actions *actions, uint16_t max_len)
 
 struct action_xlate_ctx {
     /* Input. */
+    struct rule *rule;          /* Rule to which these actions correspond. */
     struct flow flow;           /* Flow to which these actions correspond. */
     int recurse;                /* Recursion level, via xlate_table_action. */
     struct ofproto *ofproto;
@@ -2518,13 +2599,19 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
         ctx->flow.in_port = old_in_port;
 
         if (rule) {
-            if (rule->super) {
-                rule = rule->super;
-            }
+            struct rule *ctx_rule;
 
+            ctx_rule = ctx->rule;
+            ctx->rule = ctx->rule ? rule : NULL;
             ctx->recurse++;
             do_xlate_actions(rule->actions, rule->n_actions, ctx);
             ctx->recurse--;
+            ctx->rule = ctx_rule;
+
+            if (ctx->rule) {
+                add_resubmit_rule(ctx->ofproto, rule, ctx->rule);
+            }
+
         }
     } else {
         struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
@@ -2835,8 +2922,8 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
 
 static int
 xlate_actions(const union ofp_action *in, size_t n_in,
-              const struct flow *flow, struct ofproto *ofproto,
-              const struct ofpbuf *packet,
+              struct rule *rule, const struct flow *flow,
+              struct ofproto *ofproto, const struct ofpbuf *packet,
               struct odp_actions *out, tag_type *tags, bool *may_set_up_flow,
               uint16_t *nf_output_iface)
 {
@@ -2844,6 +2931,7 @@ xlate_actions(const union ofp_action *in, size_t n_in,
     struct action_xlate_ctx ctx;
     COVERAGE_INC(ofproto_ofp2odp);
     odp_actions_init(out);
+    ctx.rule = rule;
     ctx.flow = *flow;
     ctx.recurse = 0;
     ctx.ofproto = ofproto;
@@ -2935,7 +3023,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
 
     flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
     error = xlate_actions((const union ofp_action *) opo->actions, n_actions,
-                          &flow, p, &payload, &actions, NULL, NULL, NULL);
+                          NULL, &flow, p, &payload, &actions, NULL, NULL, NULL);
     if (error) {
         return error;
     }
@@ -3182,7 +3270,7 @@ query_stats(struct ofproto *p, struct rule *rule,
             uint64_t *packet_countp, uint64_t *byte_countp)
 {
     uint64_t packet_count, byte_count;
-    struct rule *subrule;
+    struct rule *subrule, *rs_rule;
     struct odp_flow *odp_flows;
     size_t n_odp_flows;
 
@@ -3223,6 +3311,16 @@ query_stats(struct ofproto *p, struct rule *rule,
     }
     free(odp_flows);
 
+    LIST_FOR_EACH (rs_rule, rs_node, &rule->rs_children) {
+        uint64_t rs_packet_count, rs_byte_count;
+
+        assert(rs_rule->rs_parent == rule);
+
+        query_stats(p, rs_rule, &rs_packet_count, &rs_byte_count);
+        packet_count += rs_packet_count;
+        byte_count   += rs_byte_count;
+    }
+
     /* Return the stats to the caller. */
     *packet_countp = packet_count;
     *byte_countp = byte_count;
-- 
1.7.3.1





More information about the dev mailing list