Implement OFPP_NORMAL action in secchan and hook into vswitchd.
authorBen Pfaff <blp@nicira.com>
Tue, 10 Mar 2009 21:03:13 +0000 (14:03 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 10 Mar 2009 21:04:19 +0000 (14:04 -0700)
Bonded interface accounting and rebalancing has been removed and needs to
be added back in.

Handling of ARP packets arriving on bonded interfaces is also known to
be broken.

secchan/ofproto.c
secchan/ofproto.h
vswitchd/automake.mk
vswitchd/bridge.c
vswitchd/flowtrack.c [deleted file]
vswitchd/flowtrack.h [deleted file]

index 36794ae6c7b0732e2d4fa1f28e6dd2947e7a2e9c..24637d89687a609debe140bf751ed02544b8fe62 100644 (file)
@@ -62,6 +62,7 @@
 #include "shash.h"
 #include "status.h"
 #include "svec.h"
+#include "tag.h"
 #include "timeval.h"
 #include "vconn.h"
 #include "vconn-ssl.h"
@@ -90,7 +91,8 @@ static void hton_ofp_phy_port(struct ofp_phy_port *);
 
 static void xlate_actions(const union ofp_action *in, size_t n_in,
                           const flow_t *flow, struct ofproto *ofproto,
-                          struct odp_actions *out);
+                          bool revalidating,
+                          struct odp_actions *out, tag_type *tags);
 
 #define UNKNOWN_SUPER ((struct rule *)-1)
 struct rule {
@@ -104,6 +106,7 @@ struct rule {
     uint64_t byte_count;        /* Bytes from *expired* subrules. */
     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). */
 
     struct rule *super;
     struct list list;
@@ -116,8 +119,8 @@ struct rule {
 static void rule_free(struct rule *);
 static void rule_destroy(struct rule *);
 static struct rule *rule_from_cls_rule(const struct cls_rule *);
-static void rule_make_actions(struct ofproto *,
-                              const struct rule *, struct odp_actions *);
+static void rule_make_actions(struct ofproto *, struct rule *,
+                              bool revalidating, struct odp_actions *);
 
 struct ofconn {
     struct list node;
@@ -185,8 +188,8 @@ static void send_packet_in_miss(struct ofpbuf *, void *ofproto);
 static void send_packet_in_action(struct ofpbuf *, void *ofproto);
 static void update_used(struct ofproto *);
 static void expire_rule(struct cls_rule *, void *ofproto);
-static bool revalidate_subrule(struct ofproto *p, struct rule *subrule);
-static void revalidate_subrule_cb(struct cls_rule *sub_, void *p_);
+static bool revalidate_rule(struct ofproto *p, struct rule *rule);
+static void revalidate_cb(struct cls_rule *rule_, void *p_);
 
 static void handle_odp_msg(struct ofproto *, struct ofpbuf *);
 
@@ -615,6 +618,16 @@ ofproto_destroy(struct ofproto *p)
 
 int
 ofproto_run(struct ofproto *p)
+{
+    int error = ofproto_run1(p);
+    if (!error) {
+        error = ofproto_run2(p, false, NULL);
+    }
+    return error;
+}
+
+int
+ofproto_run1(struct ofproto *p)
 {
     struct ofconn *ofconn, *next_ofconn;
     char *devname;
@@ -706,8 +719,32 @@ ofproto_run(struct ofproto *p)
         classifier_for_each(&p->cls, CLS_INC_EXACT, expire_rule, p);
     }
 
-    if (p->need_revalidate) {
-        classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_subrule_cb, p);
+    return 0;
+}
+
+struct revalidate_cbdata {
+    struct ofproto *ofproto;
+    bool revalidate_all;        /* Revalidate all exact-match rules? */
+    bool revalidate_subrules;   /* Revalidate all exact-match subrules? */
+    struct tag_set revalidate_set; /* Set of tags to revalidate. */
+};
+
+int
+ofproto_run2(struct ofproto *p,
+             bool revalidate_all, const struct tag_set *revalidate_set)
+{
+    if (p->need_revalidate || revalidate_all
+        || (revalidate_set && !tag_set_is_empty(revalidate_set))) {
+        struct revalidate_cbdata cbdata;
+        cbdata.ofproto = p;
+        cbdata.revalidate_all = revalidate_all;
+        cbdata.revalidate_subrules = p->need_revalidate;
+        if (revalidate_set) {
+            cbdata.revalidate_set = *revalidate_set;
+        } else {
+            tag_set_init(&cbdata.revalidate_set);
+        }
+        classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_cb, &cbdata);
         p->need_revalidate = false;
     }
 
@@ -765,7 +802,7 @@ ofproto_send_packet(struct ofproto *p, const flow_t *flow,
     struct odp_actions odp_actions;
     int error;
 
-    xlate_actions(actions, n_actions, flow, p, &odp_actions);
+    xlate_actions(actions, n_actions, flow, p, false, &odp_actions, NULL);
     error = dpif_execute(&p->dpif, flow->in_port, odp_actions.actions,
                          odp_actions.n_actions, packet);
     odp_actions_free(&odp_actions);
@@ -791,6 +828,7 @@ ofproto_add_flow(struct ofproto *p,
     rule->byte_count = 0;
     rule->tcp_flags = 0;
     rule->ip_tos = 0;
+    rule->tags = 0;
     rule->super = NULL;         /* XXX */
     list_init(&rule->list);
     rule->n_actions = n_actions;
@@ -803,7 +841,7 @@ ofproto_add_flow(struct ofproto *p,
     }
 
     if (!wildcards) {
-        rule_make_actions(p, rule, &odp_actions);
+        rule_make_actions(p, rule, false, &odp_actions);
         if (packet) {
             if (!ofproto_send_packet(p, flow, actions, n_actions, packet)) {
                 rule->byte_count = packet->size;
@@ -838,7 +876,8 @@ ofproto_set_actions(struct ofproto *ofproto, const flow_t *flow,
     rule->n_actions = n_actions;
     rule->actions = xmemdup(actions, n_actions * sizeof *rule->actions);
 
-    rule_make_actions(ofproto, rule, &odp_actions);
+    rule->tags = 0;
+    rule_make_actions(ofproto, rule, false, &odp_actions);
     dpif_flow_set_actions(&ofproto->dpif, flow, odp_actions.actions,
                           odp_actions.n_actions);
     odp_actions_free(&odp_actions);
@@ -1228,13 +1267,14 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port)
 }
 
 static void
-rule_make_actions(struct ofproto *p,
-                  const struct rule *rule, struct odp_actions *actions)
+rule_make_actions(struct ofproto *p, struct rule *rule, bool revalidating,
+                  struct odp_actions *actions)
 {
     const struct rule *super = rule->super ? rule->super : rule;
     assert(!rule->cr.wc.wildcards);
+    rule->tags = 0;
     xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p,
-                  actions);
+                  revalidating, actions, &rule->tags);
 }
 \f
 static void
@@ -1417,20 +1457,21 @@ add_controller_action(struct odp_actions *actions,
 
 struct action_xlate_ctx {
     /* Input. */
-    const union ofp_action *in; /* OpenFlow actions. */
-    size_t n_in;                /* Number of elements in 'in' array. */
     const flow_t *flow;         /* Flow to which these actions correspond. */
     int recurse;                /* Recursion level, via xlate_table_action. */
     struct ofproto *ofproto;
+    bool revalidating;
 
     /* Output. */
     struct odp_actions *out;    /* Datapath actions. */
+    tag_type *tags;             /* Tags associated with OFPP_NORMAL actions. */
 };
 
-static void do_xlate_actions(struct action_xlate_ctx *ctx);
+static void do_xlate_actions(const union ofp_action *in, size_t n_in,
+                             struct action_xlate_ctx *ctx);
 
 static void
-xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port)
+xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
 {
     struct ofproto *p = ctx->ofproto;
     struct action_xlate_ctx nested_ctx;
@@ -1449,7 +1490,7 @@ xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port)
         return;
     } else if (rule->super && p->need_revalidate) {
         /* This might be a subrule that is now invalid.  Revalidate it. */
-        if (!revalidate_subrule(p, rule)) {
+        if (!revalidate_rule(p, rule)) {
             /* The subrule got deleted so we can optimize slightly by only
              * looking through the wildcarded rules. */
             rule = rule_from_cls_rule(classifier_lookup_wild(&p->cls, &flow));
@@ -1462,17 +1503,13 @@ xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port)
         rule = rule->super;
     }
 
-    nested_ctx.in = rule->actions;
-    nested_ctx.n_in = rule->n_actions;
-    nested_ctx.flow = ctx->flow;
-    nested_ctx.recurse = ctx->recurse + 1;
-    nested_ctx.ofproto = ctx->ofproto;
-    nested_ctx.out = ctx->out;
-    do_xlate_actions(&nested_ctx);
+    ctx->recurse++;
+    do_xlate_actions(rule->actions, rule->n_actions, &nested_ctx);
+    ctx->recurse--;
 }
 
 static void
-xlate_output_action(const struct action_xlate_ctx *ctx,
+xlate_output_action(struct action_xlate_ctx *ctx,
                     const struct ofp_action_output *oao)
 {
     uint16_t odp_port;
@@ -1485,7 +1522,13 @@ xlate_output_action(const struct action_xlate_ctx *ctx,
         xlate_table_action(ctx, ctx->flow->in_port);
         break;
     case OFPP_NORMAL:
-        add_output_group_action(ctx->out, DP_GROUP_FLOOD); /* XXX */
+        if (ctx->ofproto->ofhooks->normal_cb) {
+            ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->revalidating,
+                                             ctx->out, ctx->tags,
+                                             ctx->ofproto->aux);
+        } else {
+            add_output_group_action(ctx->out, DP_GROUP_FLOOD);
+        }
         break;
     case OFPP_FLOOD:
         add_output_group_action(ctx->out, DP_GROUP_FLOOD);
@@ -1509,7 +1552,7 @@ xlate_output_action(const struct action_xlate_ctx *ctx,
 }
 
 static void
-xlate_nicira_action(const struct action_xlate_ctx *ctx,
+xlate_nicira_action(struct action_xlate_ctx *ctx,
                     const struct nx_action_header *nah)
 {
     const struct nx_action_snat *nas;
@@ -1537,14 +1580,13 @@ xlate_nicira_action(const struct action_xlate_ctx *ctx,
 }
 
 static void
-do_xlate_actions(struct action_xlate_ctx *ctx)
+do_xlate_actions(const union ofp_action *in, size_t n_in,
+                 struct action_xlate_ctx *ctx)
 {
     struct actions_iterator iter;
     const union ofp_action *ia;
 
-    for (ia = actions_first(&iter, ctx->in, ctx->n_in); ia;
-         ia = actions_next(&iter))
-    {
+    for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
         uint16_t type = ntohs(ia->type);
         union odp_action *oa;
 
@@ -1602,18 +1644,19 @@ do_xlate_actions(struct action_xlate_ctx *ctx)
 
 static void
 xlate_actions(const union ofp_action *in, size_t n_in,
-              const flow_t *flow, struct ofproto *ofproto,
-              struct odp_actions *out)
+              const flow_t *flow, struct ofproto *ofproto, bool revalidating,
+              struct odp_actions *out, tag_type *tags)
 {
+    tag_type no_tags = 0;
     struct action_xlate_ctx ctx;
     odp_actions_init(out);
-    ctx.in = in;
-    ctx.n_in = n_in;
     ctx.flow = flow;
     ctx.recurse = 0;
     ctx.ofproto = ofproto;
+    ctx.revalidating = revalidating;
     ctx.out = out;
-    do_xlate_actions(&ctx);
+    ctx.tags = tags ? tags : &no_tags;
+    do_xlate_actions(in, n_in, &ctx);
 }
 
 static int
@@ -1647,7 +1690,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
 
     flow_extract(&payload, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
     xlate_actions((const union ofp_action *) opo->actions, n_actions, &flow,
-                  p, &actions);
+                  p, false, &actions, NULL);
     dpif_execute(&p->dpif, flow.in_port, actions.actions, actions.n_actions,
                  &payload);
     odp_actions_free(&actions);
@@ -2120,7 +2163,8 @@ send_buffered(struct ofproto *p, struct ofconn *ofconn, uint32_t buffer_id,
     }
 
     flow_extract(packet, in_port, &flow);
-    xlate_actions(rule->actions, rule->n_actions, &flow, p, &actions);
+    xlate_actions(rule->actions, rule->n_actions, &flow, p, false,
+                  &actions, NULL);
     error = dpif_execute(&p->dpif, in_port,
                          actions.actions, actions.n_actions, packet);
     if (!error) {
@@ -2148,6 +2192,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn,
     rule->byte_count = 0;
     rule->tcp_flags = 0;
     rule->ip_tos = 0;
+    rule->tags = 0;
     rule->super = NULL;
     list_init(&rule->list);
     rule->n_actions = n_actions;
@@ -2186,7 +2231,7 @@ add_flow(struct ofproto *p, struct ofconn *ofconn,
         struct odp_actions actions;
 
         xlate_actions((const union ofp_action *) ofm->actions, n_actions,
-                      &rule->cr.flow, p, &actions);
+                      &rule->cr.flow, p, false, &actions, NULL);
 
         odp_flow.key = rule->cr.flow;
         odp_flow.actions = actions.actions;
@@ -2232,7 +2277,7 @@ modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm,
             struct odp_actions actions;
 
             xlate_actions((const union ofp_action *) ofm->actions, n_actions,
-                          &rule->cr.flow, p, &actions);
+                          &rule->cr.flow, p, false, &actions, NULL);
             odp_flow.key = rule->cr.flow;
             odp_flow.actions = actions.actions;
             odp_flow.n_actions = actions.n_actions;
@@ -2530,6 +2575,7 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
         subrule->packet_count = subrule->byte_count = 0;
         subrule->tcp_flags = 0;
         subrule->ip_tos = 0;
+        subrule->tags = 0;
         subrule->super = rule;
         subrule->n_actions = 0;
         subrule->actions = NULL;
@@ -2542,7 +2588,7 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
                 free(subrule);
 
                 /* Execute old_sr on packet. */
-                rule_make_actions(p, old_sr, &actions);
+                rule_make_actions(p, old_sr, false, &actions);
                 dpif_execute(&p->dpif, msg->port,
                              actions.actions, actions.n_actions, &payload);
                 odp_actions_free(&actions);
@@ -2558,17 +2604,16 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
         rule->used = time_msec();
 
         /* Install flow entry into datapath. */
-        rule_make_actions(p, subrule, &actions);
+        rule_make_actions(p, subrule, false, &actions);
         odp_flow.key = flow;
         odp_flow.actions = actions.actions;
         odp_flow.n_actions = actions.n_actions;
         dpif_flow_add(&p->dpif, &odp_flow);
     } else {
-        /* XXX This should happen only if a flow got dropped--perhaps a hash
-         * collision?  Oh, it could also indicate that the packet was buffered
-         * before we processed another packet from the same flow. */
+        /* A flow got dropped due to a hash collision, or the packet was
+         * buffered before we processed another packet from the same flow. */
         subrule = rule;
-        rule_make_actions(p, subrule, &actions);
+        rule_make_actions(p, subrule, false, &actions);
     }
 
     /* Execute subrule on packet. */
@@ -2579,49 +2624,50 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
 }
 \f
 static void
-revalidate_subrule_cb(struct cls_rule *sub_, void *p_)
+revalidate_cb(struct cls_rule *sub_, void *cbdata_)
 {
     struct rule *sub = rule_from_cls_rule(sub_);
-    struct ofproto *p = p_;
+    struct revalidate_cbdata *cbdata = cbdata_;
 
-    if (sub->super) {
-        revalidate_subrule(p, sub);
+    if (cbdata->revalidate_all
+        || (cbdata->revalidate_subrules && sub->super)
+        || (tag_set_intersects(&cbdata->revalidate_set, sub->tags))) {
+        revalidate_rule(cbdata->ofproto, sub);
     }
 }
 
 static bool
-revalidate_subrule(struct ofproto *p, struct rule *sub)
+revalidate_rule(struct ofproto *p, struct rule *rule)
 {
-    const flow_t *flow = &sub->cr.flow;
-    struct rule *super;
+    const flow_t *flow = &rule->cr.flow;
+    struct odp_actions actions;
 
-    super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow));
-    if (super != sub->super) {
+    if (rule->super) {
+        struct rule *super;
+        super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow));
         if (!super) {
             struct odp_flow odp_flow;
             memset(&odp_flow.stats, 0, sizeof odp_flow.stats);
-            odp_flow.key = sub->cr.flow;
+            odp_flow.key = rule->cr.flow;
             odp_flow.actions = NULL;
             odp_flow.n_actions = 0;
             dpif_flow_del(&p->dpif, &odp_flow);
-            classifier_remove(&p->cls, &sub->cr);
-            rule_destroy(sub);
+            classifier_remove(&p->cls, &rule->cr);
+            rule_destroy(rule);
             return false;
         } else {
-            struct odp_actions actions;
-
-            sub->super = super;
-            sub->hard_timeout = super->hard_timeout;
-            sub->idle_timeout = super->idle_timeout;
-            sub->created = super->created;
-            sub->used = 0;
-
-            rule_make_actions(p, sub, &actions);
-            dpif_flow_set_actions(&p->dpif, flow, actions.actions,
-                                  actions.n_actions);
-            odp_actions_free(&actions);
+            rule->super = super;
+            rule->hard_timeout = super->hard_timeout;
+            rule->idle_timeout = super->idle_timeout;
+            rule->created = super->created;
+            rule->used = 0;
         }
     }
+
+    rule_make_actions(p, rule, true, &actions);
+    dpif_flow_set_actions(&p->dpif, flow, actions.actions,
+                          actions.n_actions);
+    odp_actions_free(&actions);
     return true;
 }
 
@@ -2771,7 +2817,6 @@ update_used(struct ofproto *p)
         }
 
         update_time(rule, &f->stats);
-        /* XXX update p->next_expiration */
     }
     free(flows);
 }
index 8f977a7a68fcfb200b0079d99eb23ec563b4ab77..c9a5d8ac5833131516e3ceb8ff62dcbfecd2bd82 100644 (file)
@@ -38,6 +38,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include "flow.h"
+#include "tag.h"
 
 struct odp_actions;
 struct ofhooks;
@@ -58,6 +59,9 @@ int ofproto_create(const char *datapath, const struct ofhooks *, void *aux,
                    struct ofproto **ofprotop);
 void ofproto_destroy(struct ofproto *);
 int ofproto_run(struct ofproto *);
+int ofproto_run1(struct ofproto *);
+int ofproto_run2(struct ofproto *,
+                 bool revalidate_all, const struct tag_set *revalidate_set);
 void ofproto_wait(struct ofproto *);
 bool ofproto_is_alive(const struct ofproto *);
 
@@ -111,6 +115,8 @@ struct ofhooks {
     bool (*packet_in_cb)(const flow_t *, const struct ofpbuf *payload,
                          void *aux);
     void (*flow_expired_cb)(const struct ofexpired *, void *aux);
+    void (*normal_cb)(const flow_t *, bool revalidating,
+                      struct odp_actions *, tag_type *, void *aux);
 };
 
 #endif /* ofproto.h */
index 8885f38464c4ce73ee2802cb003beb479ffa91fb..9a52500d75a82e97f1cb2b7c8ba2f73b797854c5 100644 (file)
@@ -8,8 +8,6 @@ vswitchd_vswitchd_SOURCES = \
        vswitchd/brcompat.h \
        vswitchd/bridge.c \
        vswitchd/bridge.h \
-       vswitchd/flowtrack.c \
-       vswitchd/flowtrack.h \
        vswitchd/vswitchd.c
 vswitchd_vswitchd_LDADD = \
        secchan/libsecchan.a \
index dc75e86897ec2cdd72d5ff014a647331e83ea221..0ed0a332b911910f7e3b6f9c597cd4b4cd381587 100644 (file)
@@ -46,7 +46,6 @@
 #include "dirs.h"
 #include "dpif.h"
 #include "flow.h"
-#include "flowtrack.h"
 #include "hash.h"
 #include "list.h"
 #include "mac-learning.h"
 #define THIS_MODULE VLM_bridge
 #include "vlog.h"
 
+struct dst {
+    uint16_t vlan;
+    uint16_t dp_ifidx;
+};
+
 struct iface {
     struct port *port;          /* Containing port. */
     size_t port_ifidx;          /* Index within containing port. */
@@ -167,7 +171,6 @@ struct bridge {
     size_t n_ports, allocated_ports;
 
     /* Flow tracking. */
-    struct ft *ft;
     struct tag_set revalidate_set;
     bool flush;
 
@@ -200,11 +203,6 @@ static void bridge_flush(struct bridge *);
 static void bridge_pick_local_hw_addr(struct bridge *,
                                       struct iface *local_iface);
 
-static void revalidate_flow(struct bridge *, struct ft_flow *);
-
-static void flowstats_run(struct bridge *);
-static void flowstats_wait(struct bridge *);
-
 static void bond_run(struct bridge *);
 static void bond_wait(struct bridge *);
 
@@ -225,8 +223,6 @@ static void brstp_reconfigure(struct bridge *);
 static void brstp_adjust_timers(struct bridge *);
 static void brstp_run(struct bridge *);
 static void brstp_wait(struct bridge *);
-static void brstp_receive(struct bridge *, const flow_t *,
-                          const struct ofpbuf *);
 
 static void iface_create(struct port *, const char *name);
 static void iface_destroy(struct iface *);
@@ -559,7 +555,6 @@ bridge_wait(void)
         if (br->ml) {
             mac_learning_wait(br->ml);
         }
-        flowstats_wait(br);
         bond_wait(br);
         brstp_wait(br);
         if (!tag_set_is_empty(&br->revalidate_set)) {
@@ -624,7 +619,6 @@ bridge_create(const char *name)
 
     port_array_init(&br->ifaces);
 
-    br->ft = ft_create();
     tag_set_init(&br->revalidate_set);
     br->flush = false;
 
@@ -653,7 +647,6 @@ bridge_destroy(struct bridge *br)
         dpif_close(&br->dpif);
         ofproto_destroy(br->ofproto);
         free(br->controller);
-        ft_destroy(br->ft);
         mac_learning_destroy(br->ml);
         port_array_destroy(&br->ifaces);
         free(br->ports);
@@ -700,31 +693,18 @@ bridge_run_one(struct bridge *br)
 {
     int error;
 
-    if (br->controller) {
-        return ofproto_run(br->ofproto);
+    error = ofproto_run1(br->ofproto);
+    if (error) {
+        return error;
     }
 
-    /* Now do the things that may want to revalidate flows. */
-    error = ofproto_run(br->ofproto);
-    hmap_shrink(&br->ft->flows);
     if (br->ml) {
         mac_learning_run(br->ml, &br->revalidate_set);
     }
-    flowstats_run(br);
     bond_run(br);
     brstp_run(br);
 
-    /* Now revalidate any flows that need it. */
-    if (br->flush || !tag_set_is_empty(&br->revalidate_set)) {
-        struct ft_flow *f, *next;
-
-        HMAP_FOR_EACH_SAFE (f, next, struct ft_flow, node, &br->ft->flows) {
-            if (br->flush
-                || tag_set_intersects(&br->revalidate_set, f->tags)) {
-                revalidate_flow(br, f);
-            }
-        }
-    }
+    error = ofproto_run2(br->ofproto, br->flush, &br->revalidate_set);
     tag_set_init(&br->revalidate_set);
     br->flush = false;
 
@@ -890,16 +870,28 @@ bridge_reconfigure_one(struct bridge *br)
         } else {
             ofproto_set_remote_execution(br->ofproto, NULL, NULL);
         }
-    } else {
+
         if (br->controller) {
-            /* There was a controller configured, so we want to disconnect
-             * from it so that connect_ofproto() will set up a "loopback"
-             * connection to us over a socketpair. */
-            ofproto_set_controller(br->ofproto, NULL);
-        } else {
-            /* No controller configured before either, so we're already doing
-             * the right thing. */
+            /* Get rid of our match-everything flow, and all the rest while
+             * we're at it (which should mostly be subflows set up by that
+             * one). */
+            ofproto_flush_flows(br->ofproto);
         }
+    } else {
+        union ofp_action action;
+        flow_t flow;
+
+        /* Set up a flow that matches every packet and directs them to
+         * OFPP_NORMAL (which goes to us). */
+        memset(&action, 0, sizeof action);
+        action.type = htons(OFPAT_OUTPUT);
+        action.output.len = htons(sizeof action);
+        action.output.port = htons(OFPP_NORMAL);
+        memset(&flow, 0, sizeof flow);
+        ofproto_add_flow(br->ofproto, &flow, OFPFW_ALL, 0,
+                         &action, 1, NULL, 0);
+
+        ofproto_set_controller(br->ofproto, NULL);
         ofproto_set_in_band(br->ofproto, false);
         ofproto_set_max_backoff(br->ofproto, 1);
         ofproto_set_probe_interval(br->ofproto, 5);
@@ -987,27 +979,6 @@ bridge_fetch_dp_ifaces(struct bridge *br)
     }
     free(dpif_ports);
 }
-
-/* Returns the idle time that the bridge is currently using.  We reduce the
- * idle time as the flow table grows, so as to act as a brake on further flow
- * table growth. */
-static int
-bridge_idle_time(const struct bridge *br)
-{
-    int idle_time = br->flow_idle_time;
-    if (idle_time) {
-        size_t n_flows = hmap_count(&br->ft->flows);
-        int step = MAX(1, br->flow_idle_time / 5);
-        while (n_flows > 1000 && idle_time > 0) {
-            idle_time -= step;
-            n_flows /= 2;
-        }
-        if (idle_time < 1) {
-            idle_time = 1;
-        }
-    }
-    return idle_time;
-}
 \f
 /* Bridge packet processing functions. */
 
@@ -1060,26 +1031,6 @@ choose_output_iface(const struct port *port, const flow_t *flow,
     return true;
 }
 
-static void
-bond_account_flow(struct bridge *br, const struct ft_flow *f)
-{
-    const struct ft_dst *dst;
-
-    if (f->byte_count <= f->last_byte_count) {
-        /* No bytes to add, so don't waste our time. */
-        return;
-    }
-    /* XXX return immediately if no bonded interfaces. */
-
-    for (dst = &f->dsts[0]; dst < &f->dsts[f->n_dsts]; dst++) {
-        struct port *port = port_from_dp_ifidx(br, dst->dp_ifidx);
-        if (port && port->n_ifaces >= 2) {
-            struct bond_entry *e = lookup_bond_entry(port, f->flow.dl_src);
-            e->tx_bytes += f->byte_count - f->last_byte_count;
-        }
-    }
-}
-
 static void
 bond_link_status_update(struct iface *iface, bool carrier)
 {
@@ -1183,7 +1134,7 @@ bond_wait(struct bridge *br)
 }
 
 static bool
-set_dst(struct ft_dst *p, const flow_t *flow,
+set_dst(struct dst *p, const flow_t *flow,
         const struct port *in_port, const struct port *out_port,
         tag_type *tags)
 {
@@ -1206,28 +1157,28 @@ set_dst(struct ft_dst *p, const flow_t *flow,
 }
 
 static void
-swap_dst(struct ft_dst *p, struct ft_dst *q)
+swap_dst(struct dst *p, struct dst *q)
 {
-    struct ft_dst tmp = *p;
+    struct dst tmp = *p;
     *p = *q;
     *q = tmp;
 }
 
-/* Moves all the ft_dsts with vlan == 'vlan' to the front of the 'n_dsts' in
+/* Moves all the dsts with vlan == 'vlan' to the front of the 'n_dsts' in
  * 'dsts'.  (This may help performance by reducing the number of VLAN changes
  * that we push over OpenFlow.  We could in fact fully sort the array by vlan,
  * but in most cases there are at most two different vlan tags so that's
  * possibly overkill.) */
 static void
-partition_dsts(struct ft_dst *dsts, size_t n_dsts, int vlan)
+partition_dsts(struct dst *dsts, size_t n_dsts, int vlan)
 {
-    struct ft_dst *first = dsts;
-    struct ft_dst *last = dsts + n_dsts;
+    struct dst *first = dsts;
+    struct dst *last = dsts + n_dsts;
 
     while (first != last) {
         /* Invariants:
-         *      - All ft_dsts < first have vlan == 'vlan'.
-         *      - All ft_dsts >= last have vlan != 'vlan'.
+         *      - All dsts < first have vlan == 'vlan'.
+         *      - All dsts >= last have vlan != 'vlan'.
          *      - first < last. */
         while (first->vlan == vlan) {
             if (++first == last) {
@@ -1250,36 +1201,6 @@ partition_dsts(struct ft_dst *dsts, size_t n_dsts, int vlan)
     }
 }
 
-static void *
-add_action_header(struct ofpbuf *buf, uint16_t type)
-{
-    struct ofp_action_header *oah = ofpbuf_put_zeros(buf, sizeof *oah);
-    oah->type = htons(type);
-    oah->len = htons(sizeof *oah);
-    return oah;
-}
-
-static void
-add_output_action(struct ofpbuf *buf, uint16_t dp_ifidx)
-{
-    struct ofp_action_output *oao = add_action_header(buf, OFPAT_OUTPUT);
-    oao->port = htons(dp_ifidx);
-    oao->max_len = htons(0);
-}
-
-static void
-add_vlan_action(struct ofpbuf *buf, uint16_t old_vlan, uint16_t new_vlan)
-{
-    assert(old_vlan != new_vlan);
-    if (new_vlan == htons(OFP_VLAN_NONE)) {
-        add_action_header(buf, OFPAT_STRIP_VLAN);
-    } else {
-        struct ofp_action_vlan_vid *oavv
-            = add_action_header(buf, OFPAT_SET_VLAN_VID);
-        oavv->vlan_vid = htons(new_vlan);
-    }
-}
-
 static int
 mirror_mask_ffs(mirror_mask_t mask)
 {
@@ -1288,8 +1209,8 @@ mirror_mask_ffs(mirror_mask_t mask)
 }
 
 static bool
-dst_is_duplicate(const struct ft_dst *dsts, size_t n_dsts,
-                 const struct ft_dst *test)
+dst_is_duplicate(const struct dst *dsts, size_t n_dsts,
+                 const struct dst *test)
 {
     size_t i;
     for (i = 0; i < n_dsts; i++) {
@@ -1315,15 +1236,15 @@ port_includes_vlan(const struct port *port, uint16_t vlan)
 static size_t
 compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
              const struct port *in_port, const struct port *out_port,
-             struct ft_dst dsts[], tag_type *tags)
+             struct dst dsts[], tag_type *tags)
 {
     mirror_mask_t mirrors = in_port->src_mirrors;
-    struct ft_dst *dst = dsts;
+    struct dst *dst = dsts;
     size_t i;
 
     *tags |= in_port->stp_state_tag;
     if (out_port == FLOOD_PORT) {
-        /* XXX use OFPP_FLOOD if no vlans or bonding. */
+        /* XXX use ODP_FLOOD if no vlans or bonding. */
         /* XXX even better, define each VLAN as a datapath port group */
         for (i = 0; i < br->n_ports; i++) {
             struct port *port = br->ports[i];
@@ -1357,12 +1278,10 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
                         if (port->vlan < 0) {
                             dst->vlan = m->out_vlan;
                         }
-                        if (dst->dp_ifidx == flow->in_port) {
-                            if (dst->vlan == vlan) {
-                                /* Don't send out input port on same VLAN. */
-                                continue;
-                            }
-                            dst->dp_ifidx = OFPP_IN_PORT;
+                        if (dst->dp_ifidx == flow->in_port
+                            && dst->vlan == vlan) {
+                            /* Don't send out input port on same VLAN. */
+                            continue;
                         }
                         dst++;
                     }
@@ -1376,129 +1295,56 @@ compose_dsts(const struct bridge *br, const flow_t *flow, uint16_t vlan,
     return dst - dsts;
 }
 
-static void
-put_actions(const struct ft_dst dsts[], size_t n_dsts, uint16_t flow_vlan,
-            struct ofpbuf *buf)
+static void UNUSED
+print_dsts(const struct dst *dsts, size_t n)
 {
-    const struct ft_dst *p;
-    uint16_t vlan = flow_vlan;
-    for (p = dsts; p < &dsts[n_dsts]; p++) {
-        if (p->vlan != vlan) {
-            add_vlan_action(buf, vlan, p->vlan);
-            vlan = p->vlan;
+    for (; n--; dsts++) {
+        printf(">p%"PRIu16, dsts->dp_ifidx);
+        if (dsts->vlan != OFP_VLAN_NONE) {
+            printf("v%"PRIu16, dsts->vlan);
         }
-        add_output_action(buf, p->dp_ifidx);
     }
 }
 
 static void
-send_packets(struct bridge *br, const flow_t *flow,
-             const struct ofpbuf *pkt, uint16_t vlan,
-             const struct port *in_port, const struct port *out_port,
-             tag_type tags, bool setup_flow)
+compose_actions(struct bridge *br, const flow_t *flow, uint16_t vlan,
+                const struct port *in_port, const struct port *out_port,
+                tag_type *tags, struct odp_actions *actions)
 {
-    struct ft_dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)];
-    size_t actions_len;         /* Estimated length of actions, in bytes. */
+    struct dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)];
     size_t n_dsts;
+    const struct dst *p;
+    uint16_t cur_vlan;
 
-    n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, &tags);
-    actions_len = (sizeof(struct ofp_action_header) + 2) * n_dsts;
-
-    if (setup_flow) {
-        enum { NO_OP, ADD_FLOW, SET_ACTIONS } command;
-        struct ft_flow *f;
-
-        f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
-        if (f) {
-            if (!ftd_equal(dsts, n_dsts, f->dsts, f->n_dsts)) {
-                /* Update the flow.  Use OFPFC_MODIFY_STRICT instead of
-                 * OFPFC_ADD so that we don't reset the idle-timer
-                 * countdown for this flow. */
-                ftf_set_dsts(f, dsts, n_dsts);
-                command = SET_ACTIONS;
-            } else {
-                /* Correct flow is already in the flow table, nothing to do.
-                 * This should only happen on revalidate, since
-                 * process_packet_in() will delete any flow entry for a
-                 * no-match packet-in message.  (If it could happen in other
-                 * circumstances then we'd want to arrange to send a packet-out
-                 * below, but there's no need.) */
-                command = NO_OP;
-            }
-            f->tags = tags;
-        } else {
-            f = ftf_create(flow, dsts, n_dsts, tags);
-            ft_insert(br->ft, f);
-            command = ADD_FLOW;
-        }
-        f->need_drop = false;
-
-        if (command != NO_OP) {
-            struct ofpbuf abuf;
-            size_t n_actions;
-
-            ofpbuf_init(&abuf, actions_len);
-            put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), &abuf);
-            n_actions = abuf.size / sizeof(union ofp_action);
-
-            if (command == ADD_FLOW) {
-                ofproto_add_flow(br->ofproto, flow, 0, UINT16_MAX,
-                                 abuf.data, n_actions,
-                                 pkt, bridge_idle_time(br));
-                pkt = NULL;     /* Already sent. */
+    n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, tags);
 
-                /* ofproto_add_flow() will reset the byte counters. */
-                f->last_byte_count = f->byte_count = 0;
-            } else {
-                ofproto_set_actions(br->ofproto, flow, abuf.data, n_actions);
-            }
-            ofpbuf_uninit(&abuf);
-        }
-    } else {
-        struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
-        if (f) {
-            /* XXX delete flow from ft, queue delete-flow openflow message */
+    cur_vlan = ntohs(flow->dl_vlan);
+    for (p = dsts; p < &dsts[n_dsts]; p++) {
+        union odp_action *a;
+        if (p->vlan != cur_vlan) {
+            a = odp_actions_add(actions, ODPAT_SET_VLAN_VID);
+            a->vlan_vid.vlan_vid = htons(p->vlan);
+            cur_vlan = p->vlan;
         }
+        a = odp_actions_add(actions, ODPAT_OUTPUT);
+        a->output.port = p->dp_ifidx;
     }
-
-    /* XXX we should send the packet *before* we set up the flow, so as to not
-     * reorder packets in the flow. */
-    if (pkt) {
-        struct ofpbuf abuf;
-
-        ofpbuf_init(&abuf, actions_len);
-        put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), &abuf);
-        ofproto_send_packet(br->ofproto, flow,
-                            abuf.data, abuf.size / sizeof(union ofp_action),
-                            pkt);
-        ofpbuf_uninit(&abuf);
-    }
-}
-
-static bool
-is_bcast_arp_reply(const flow_t *flow, const struct ofpbuf *pkt)
-{
-    return (flow->dl_type == htons(ETH_TYPE_ARP)
-            && eth_addr_is_broadcast(flow->dl_dst)
-            && pkt->size >= sizeof(struct arp_eth_header)
-            && ((struct arp_eth_header *) pkt->data)->ar_op == ARP_OP_REQUEST);
 }
 
 static void
-process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
+process_flow(struct bridge *br, const flow_t *flow, bool revalidating,
+             struct odp_actions *actions, tag_type *tags)
 {
     struct iface *in_iface;
     struct port *in_port;
     struct port *out_port = NULL; /* By default, drop the packet/flow. */
-    tag_type tags = 0;
     int vlan;
 
     /* Find the interface and port structure for the received packet. */
     in_iface = iface_from_dp_ifidx(br, flow->in_port);
     if (!in_iface) {
         /* No interface?  Something fishy... */
-        struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
-        if (pkt || (f && f->need_drop)) {
+        if (!revalidating) {
             /* Odd.  A few possible reasons here:
              *
              * - We deleted an interface but there are still a few packets
@@ -1514,35 +1360,9 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
 
             VLOG_WARN_RL(&rl, "bridge %s: received packet on unknown "
                          "interface %"PRIu16, br->name, flow->in_port); 
-
-            ofproto_add_flow(br->ofproto, flow, 0, UINT16_MAX,
-                             NULL, 0, NULL, bridge_idle_time(br));
-            if (f) {
-                ftf_set_dsts(f, NULL, 0);
-                f->tags = tags;
-            } else {
-                f = ftf_create(flow, NULL, 0, tags);
-                ft_insert(br->ft, f);
-            }
-
-            /* Mark the flow as being needed to drop packets.  (If we don't do
-             * this, then the flow will be deleted as soon as we revalidate
-             * it.) */
-            f->need_drop = true;
-        } else {
-            /* We're revalidating, not receiving a fresh packet.  Most likely,
-             * this interface existed and has now been deleted from the
-             * datapath.  Drop the flow. */
-            assert(f);
-
-            ofproto_delete_flow(br->ofproto, flow, 0, UINT16_MAX);
-
-            /* ofproto_delete_flow() better not call back to
-             * bridge_flow_expired_ofhook_cb(). */
-            ft_remove(br->ft, f);
-            ftf_destroy(f);
-            /* 'flow' pointed to &f->flow, so don't access it anymore. */
         }
+
+        /* Return without adding any actions, to drop packets on this flow. */
         return;
     }
     in_port = in_iface->port;
@@ -1561,7 +1381,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
     if (in_port->vlan >= 0) {
         if (vlan) {
             /* XXX support double tagging? */
-            if (pkt) {
+            if (!revalidating) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %"PRIu16" tagged "
                              "packet received on port %s configured with "
@@ -1607,7 +1427,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
     /* Drop multicast and broadcast packets on inactive bonded interfaces, to
      * avoid receiving duplicates. */
     if (in_port->n_ifaces > 1 && eth_addr_is_multicast(flow->dl_dst)) {
-        tags |= in_port->active_iface_tag;
+        *tags |= in_port->active_iface_tag;
         if (in_port->active_iface != in_iface->port_ifidx) {
             goto done;
         }
@@ -1619,7 +1439,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
         int out_port_idx;
         bool may_learn;
 
-        if (!pkt) {
+        if (revalidating) {
             /* Don't try to learn from revalidation. */
             may_learn = false;
         } else if (in_port->n_ifaces > 1) {
@@ -1631,11 +1451,8 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
             int src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan);
             may_learn = src_idx < 0 || src_idx == in_port->port_idx;
 
-            /* Broadcast ARP replies are an exception to this rule: the host
-             * has moved to another switch. */
-            if (!may_learn && is_bcast_arp_reply(flow, pkt)) {
-                may_learn = true;
-            }
+            /* XXX Need to make an exception for broadcast ARP replies here:
+             * the host has moved to another switch. */
         } else {
             may_learn = true;
         }
@@ -1659,7 +1476,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
 
         /* Determine output port. */
         out_port_idx = mac_learning_lookup_tag(br->ml, flow->dl_dst, vlan,
-                                               &tags);
+                                               tags);
         if (out_port_idx >= 0 && out_port_idx < br->n_ports) {
             out_port = br->ports[out_port_idx];
         }
@@ -1684,17 +1501,7 @@ process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
      *     them.
      */
 done:
-    send_packets(br, flow, pkt, vlan, in_port, out_port, tags,
-                 (br->flow_idle_time >= 0
-                  && (in_port->n_ifaces < 2
-                      || flow->dl_type != htons(ETH_TYPE_ARP)
-                      || !eth_addr_is_broadcast(flow->dl_dst))));
-}
-
-static void
-revalidate_flow(struct bridge *br, struct ft_flow *f)
-{
-    process_flow(br, &f->flow, NULL);
+    compose_actions(br, flow, vlan, in_port, out_port, tags, actions);
 }
 
 /* Careful: 'opp' is in host byte order and opp->port_no is an OFP port
@@ -1735,342 +1542,30 @@ bridge_port_changed_ofhook_cb(enum ofp_port_reason reason,
     }
 }
 
-static bool
-bridge_packet_in_ofhook_cb(const flow_t *flow, const struct ofpbuf *payload,
-                           void *br_)
+static void
+bridge_normal_ofhook_cb(const flow_t *flow, bool revalidating,
+                        struct odp_actions *actions, tag_type *tags, void *br_)
 {
     struct bridge *br = br_;
-    struct ft_flow *f;
-
-    /* Delete any existing flow from the flow tracker.  The flow cannot really
-     * be in the flow table (otherwise we wouldn't be getting called). */
-    f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
-    if (f) {
-        ft_remove(br->ft, f);
-        ftf_destroy(f);
-    }
 
+#if 0
     if (flow->dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE)
         && eth_addr_equals(flow->dl_dst, stp_eth_addr)) {
         brstp_receive(br, flow, payload);
         return true;
     }
+#endif
 
-    process_flow(br, flow, payload);
-
-    return true;
-}
-
-static void
-bridge_flow_expired_ofhook_cb(const struct ofexpired *expired, void *br_)
-{
-    struct bridge *br = br_;
-    struct ft_flow *f;
-
-    f = ft_lookup(br->ft, &expired->flow, flow_hash(&expired->flow, 0));
-    if (f) {
-        /* Update statistics. */
-        f->last_byte_count = f->byte_count;
-        f->byte_count = expired->byte_count;
-        bond_account_flow(br, f);
-
-        ft_remove(br->ft, f);
-        ftf_destroy(f);
-    } else if (VLOG_IS_DBG_ENABLED()) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-        VLOG_DBG_RL(&rl, "received flow expiration for flow not in table");
-    }
+    process_flow(br, flow, revalidating, actions, tags);
 }
 
 static struct ofhooks bridge_ofhooks = {
     bridge_port_changed_ofhook_cb,
-    bridge_packet_in_ofhook_cb,
-    bridge_flow_expired_ofhook_cb,
+    NULL,
+    NULL,
+    bridge_normal_ofhook_cb,
 };
 \f
-/* Flow statistics collection. */
-
-struct slave_balance {
-    struct iface *iface;
-    uint64_t tx_bytes;
-    struct bond_entry **hashes;
-    size_t n_hashes;
-};
-
-/* Sorts pointers to pointers to bond_entries in ascending order by the
- * interface to which they are assigned, and within a single interface in
- * ascending order of bytes transmitted. */
-static int
-compare_bond_entries(const void *a_, const void *b_)
-{
-    const struct bond_entry *const *ap = a_;
-    const struct bond_entry *const *bp = b_;
-    const struct bond_entry *a = *ap;
-    const struct bond_entry *b = *bp;
-    if (a->iface_idx != b->iface_idx) {
-        return a->iface_idx > b->iface_idx ? 1 : -1;
-    } else if (a->tx_bytes != b->tx_bytes) {
-        return a->tx_bytes > b->tx_bytes ? 1 : -1;
-    } else {
-        return 0;
-    }
-}
-
-/* Sorts slave_balances in *descending* order by number of bytes
- * transmitted. */
-static int
-compare_slave_balance(const void *a_, const void *b_)
-{
-    const struct slave_balance *a = a_;
-    const struct slave_balance *b = b_;
-    return a->tx_bytes > b->tx_bytes ? -1 : a->tx_bytes < b->tx_bytes;
-}
-
-static void
-swap_bals(struct slave_balance *a, struct slave_balance *b)
-{
-    struct slave_balance tmp = *a;
-    *a = *b;
-    *b = tmp;
-}
-
-static void
-resort_bals(struct slave_balance *p, struct slave_balance *bals, size_t n_bals)
-{
-    if (n_bals > 1) {
-        for (; p > bals && p->tx_bytes > p[-1].tx_bytes; p--) {
-            swap_bals(p, p - 1);
-        }
-        for (; p < &bals[n_bals - 1] && p->tx_bytes < p[1].tx_bytes; p++) {
-            swap_bals(p, p + 1);
-        }
-    }
-}
-
-static void UNUSED
-log_bals(const char *title, const struct slave_balance *bals, size_t n_bals,
-         struct port *port)
-{
-    const struct slave_balance *b;
-
-    if (VLOG_IS_DBG_ENABLED()) {
-        VLOG_DBG("slave balance %s:", title);
-        for (b = bals; b < bals + n_bals; b++) {
-            size_t i;
-
-            VLOG_DBG("\t%s: %"PRIu64" bytes over:",
-                     b->iface->name, b->tx_bytes);
-            for (i = 0; i < b->n_hashes; i++) {
-                const struct bond_entry *e = b->hashes[i];
-                VLOG_DBG("\t\thash %td: %"PRIu64" bytes",
-                         e - port->bond_hash, e->tx_bytes);
-            }
-        }
-    }
-}
-
-static void
-bond_rebalance_port(struct port *port)
-{
-    struct slave_balance bals[DP_MAX_PORTS];
-    struct bond_entry *hashes[BOND_MASK + 1];
-    struct slave_balance *b, *least_loaded;
-    struct bond_entry *e;
-    size_t i;
-
-    for (b = bals; b < &bals[port->n_ifaces]; b++) {
-        b->iface = port->ifaces[b - bals];
-        b->tx_bytes = 0;
-        b->hashes = NULL;
-        b->n_hashes = 0;
-    }
-    for (i = 0; i <= BOND_MASK; i++) {
-        hashes[i] = &port->bond_hash[i];
-    }
-    qsort(hashes, BOND_MASK + 1, sizeof *hashes, compare_bond_entries);
-    for (i = 0; i <= BOND_MASK; i++) {
-        e = hashes[i];
-        if (e->iface_idx >= 0 && e->iface_idx < port->n_ifaces) {
-            b = &bals[e->iface_idx];
-            b->tx_bytes += e->tx_bytes;
-            if (!b->hashes) {
-                b->hashes = &hashes[i];
-            }
-            b->n_hashes++;
-        }
-    }
-
-    /* Sort in decreasing order of tx_bytes. */
-    qsort(bals, port->n_ifaces, sizeof *bals, compare_slave_balance);
-
-
-    /* Shift load from the most-heavily-loaded slaves to the
-     * least-heavily-loaded slaves. */
-    least_loaded = &bals[port->n_ifaces - 1];
-    //log_bals("before", bals, port->n_ifaces, port);
-    for (b = bals; b < least_loaded; ) {
-        uint64_t overload = b->tx_bytes - least_loaded->tx_bytes;
-        if (overload < least_loaded->tx_bytes >> 5 || overload < 100000) {
-            /* The extra load on this slave (and all less-loaded slaves),
-             * compared to that of the least-loaded slave, is less than ~3%, or
-             * it is less than ~1Mbps.  No point in rebalancing. */
-            break;
-        }
-
-        if (b->n_hashes == 1) {
-            /* This slave only carries a single MAC hash, so we can't shift any
-             * load away from it, even though we want to. */
-            b++;
-            continue;
-        }
-
-        for (i = 0; i < b->n_hashes; i++) {
-            e = b->hashes[i];
-            if (least_loaded->tx_bytes + e->tx_bytes
-                < b->tx_bytes - e->tx_bytes) {
-                /* Delete element from e->hashes. */
-                if (!i) {
-                    b->hashes++;
-                } else {
-                    memmove(b->hashes + i, b->hashes + i + 1,
-                            (b->n_hashes - (i + 1)) * sizeof *b->hashes);
-                }
-                b->n_hashes--;
-
-                /* Shift load away from 'b'. */
-                b->tx_bytes -= e->tx_bytes;
-                resort_bals(b, bals, port->n_ifaces);
-
-                /* Shift load to 'least_loaded'. */
-                tag_set_add(&port->bridge->revalidate_set, e->iface_tag);
-                e->iface_idx = least_loaded->iface->port_ifidx;
-                e->iface_tag = tag_create_random();
-                least_loaded->tx_bytes += e->tx_bytes;
-                resort_bals(least_loaded, bals, port->n_ifaces);
-                goto again;
-            }
-        }
-        b++;
-
-    again: ;
-    }
-    //log_bals("after", bals, port->n_ifaces, port);
-
-    /* Implement exponentially weighted moving average.  A weight of 1/2 causes
-     * historical data to decay to <1% in 7 rebalancing runs.  */
-    for (e = &port->bond_hash[0]; e <= &port->bond_hash[BOND_MASK]; e++) {
-        e->tx_bytes /= 2;
-    }
-}
-
-static void
-bond_rebalance(struct bridge *br)
-{
-    size_t i;
-
-    for (i = 0; i < br->n_ports; i++) {
-        struct port *port = br->ports[i];
-        if (port->n_ifaces < 2) {
-            continue;
-        }
-
-        bond_rebalance_port(port);
-    }
-}
-
-static void
-request_flow_stats(struct bridge *br)
-{
-    /* This ft_dst will never appear as a valid flow's action.  Thus, we can
-     * set it as a flow's action to force revalidation to update that flow. */
-    static const struct ft_dst invalid_dst = {0xffff, 0xffff};
-
-    struct odp_flow *flows, *odp_flow;
-    size_t n_flows;
-    int error;
-
-    tag_type flowstats_tag;
-    struct ft *new_ft;
-    size_t n_tagged;
-
-    error = dpif_flow_list_all(&br->dpif, &flows, &n_flows);
-    if (error) {
-        return;
-    }
-
-    new_ft = ft_create();
-    flowstats_tag = tag_create_random();
-    n_tagged = 0;
-    for (odp_flow = flows; odp_flow < &flows[n_flows]; odp_flow++) {
-        const flow_t *flow = &odp_flow->key;
-        size_t hash = flow_hash(flow, 0);
-        struct ft_flow *f = ft_lookup(br->ft, flow, hash);
-        if (f) {
-            /* Move from br->ft to new_ft. */
-            ft_remove(br->ft, f);
-            hmap_insert_fast(&new_ft->flows, &f->node, f->node.hash);
-
-            /* Update statistics.
-             * XXX is this still accurate with the new datapath? */
-            f->last_byte_count = f->byte_count;
-            f->byte_count = odp_flow->stats.n_bytes;
-
-            bond_account_flow(br, f);
-
-            /* XXX Should we verify that the flow's actions are what we
-             * expect?  (This used to be easy; now it's harder.) */
-        } else {
-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-            f = ft_lookup(new_ft, flow, hash);
-            if (!f) {
-                if (!VLOG_DROP_WARN(&rl)) {
-                    char *flow_string = flow_to_string(flow);
-                    VLOG_WARN("unexpected flow in flow table: %s",
-                              flow_string);
-                    free(flow_string);
-                }
-                f = ftf_create(flow, &invalid_dst, 1, flowstats_tag);
-                hmap_insert_fast(&new_ft->flows, &f->node, f->node.hash);
-                f->tags |= flowstats_tag;
-                n_tagged++;
-                f->last_byte_count = f->byte_count = odp_flow->stats.n_bytes;
-            } else {
-                VLOG_WARN_RL(&rl, "duplicate flow in flow stats reply");
-            }
-        }
-    }
-
-    /* Delete all the flows that remain in br->ft, replacing them by the ones
-     * from new_ft. */
-    hmap_expand(&new_ft->flows);
-    hmap_swap(&br->ft->flows, &new_ft->flows);
-    ft_destroy(new_ft);
-
-    /* If we tagged anything for revalidation, add that tag to the revalidation
-     * set. */
-    if (n_tagged) {
-        tag_set_add(&br->revalidate_set, flowstats_tag);
-    }
-
-    /* Rebalance any bonded ports. */
-    bond_rebalance(br);
-}
-
-static void
-flowstats_run(struct bridge *br)
-{
-    if (time_now() >= br->next_stats_request) {
-        request_flow_stats(br);
-        br->next_stats_request = time_now() + 10;
-    }
-}
-
-static void
-flowstats_wait(struct bridge *br)
-{
-    poll_timer_wait((br->next_stats_request - time_now()) * 1000);
-}
-\f
 /* Port functions. */
 
 static void
@@ -2698,7 +2193,7 @@ brstp_send_bpdu(struct ofpbuf *pkt, int port_no, void *br_)
         action.output.len = htons(sizeof action);
         action.output.port = htons(port_no);
 
-        flow_extract(pkt, htons(OFPP_NONE), &flow);
+        flow_extract(pkt, ODPP_NONE, &flow);
         ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
     }
     ofpbuf_delete(pkt);
@@ -2876,40 +2371,3 @@ brstp_wait(struct bridge *br)
         poll_timer_wait(1000);
     }
 }
-
-static void
-brstp_receive(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
-{
-    struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-    struct ofpbuf payload = *pkt;
-    struct eth_header *eth;
-    struct llc_header *llc;
-    struct stp_port *sp;
-
-    /* Find the interface and port structure for the received packet. */
-    if (flow->in_port >= STP_MAX_PORTS) {
-        return;
-    }
-    sp = stp_get_port(br->stp, flow->in_port);
-    if (stp_port_get_state(sp) == STP_DISABLED) {
-        return;
-    }
-
-    /* Check LLC DSAP.  (Caller already verified dl_type and dl_dst.) */
-    eth = payload.data;
-    llc = ofpbuf_at_assert(&payload, sizeof(struct eth_header), sizeof *llc);
-    if (llc->llc_dsap != STP_LLC_DSAP) {
-        VLOG_DBG_RL(&rl, "bad DSAP 0x%02"PRIx8" received on STP multicast "
-                    "address", llc->llc_dsap);
-        return;
-    }
-
-    /* Trim off padding on payload. */
-    if (payload.size > ntohs(eth->eth_type) + ETH_HEADER_LEN) {
-        payload.size = ntohs(eth->eth_type) + ETH_HEADER_LEN;
-    }
-    if (ofpbuf_try_pull(&payload, ETH_HEADER_LEN + LLC_HEADER_LEN)) {
-        struct stp_port *p = stp_get_port(br->stp, flow->in_port);
-        stp_received_bpdu(p, payload.data, payload.size);
-    }
-}
diff --git a/vswitchd/flowtrack.c b/vswitchd/flowtrack.c
deleted file mode 100644 (file)
index bf3cce9..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/* Copyright (c) 2008, 2009  Nicira Networks
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * In addition, as a special exception, Nicira Networks gives permission
- * to link the code of its release of vswitchd with the OpenSSL project's
- * "OpenSSL" library (or with modified versions of it that use the same
- * license as the "OpenSSL" library), and distribute the linked
- * executables.  You must obey the GNU General Public License in all
- * respects for all of the code used other than "OpenSSL".  If you modify
- * this file, you may extend this exception to your version of the file,
- * but you are not obligated to do so.  If you do not wish to do so,
- * delete this exception statement from your version.
- */
-
-#include <config.h>
-#include "flowtrack.h"
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include "flow.h"
-#include "openflow/openflow.h"
-#include "util.h"
-
-static bool
-is_vlan_action(const struct ofp_action_header *oah, uint16_t vlan)
-{
-    if (vlan == htons(OFP_VLAN_NONE)) {
-        return (oah->type == htons(OFPAT_STRIP_VLAN)
-                && oah->len != htons(sizeof *oah));
-    } else {
-        const struct ofp_action_vlan_vid *oavv
-            = (const struct ofp_action_vlan_vid *) oah;
-        return (oavv->type == htons(OFPAT_SET_VLAN_VID)
-                && oavv->len == htons(sizeof *oavv)
-                && oavv->vlan_vid == htons(vlan));
-    }
-}
-
-static bool
-is_output_action(const struct ofp_action_header *oah, uint16_t port)
-{
-    const struct ofp_action_output *oao
-        = (const struct ofp_action_output *) oah;
-    return (oao->type == htons(OFPAT_OUTPUT)
-            && oao->len == htons(sizeof *oao)
-            && oao->port == htons(port));
-}
-
-bool
-ftd_equal_actions(const struct ft_dst *dsts, size_t n_dsts,
-                  const struct ofp_action_header *oahs, size_t n_oahs,
-                  uint16_t flow_vlan)
-{
-    const struct ft_dst *dst;
-    uint16_t vlan = flow_vlan;
-    for (dst = dsts; dst < &dsts[n_dsts]; dst++) {
-        if (dst->vlan != vlan) {
-            vlan = dst->vlan;
-            if (!n_oahs-- || !is_vlan_action(oahs++, vlan)) {
-                return false;
-            }
-        }
-        if (!n_oahs-- || !is_output_action(oahs++, dst->dp_ifidx)) {
-            return false;
-        }
-    }
-    return !n_oahs;
-}
-
-void
-ftd_print(const struct ft_dst *dsts, size_t n)
-{
-    for (; n--; dsts++) {
-        printf(">p%"PRIu16, dsts->dp_ifidx);
-        if (dsts->vlan != OFP_VLAN_NONE) {
-            printf("v%"PRIu16, dsts->vlan);
-        }
-    }
-}
-
-struct ft_flow *
-ftf_create(const flow_t *flow,
-           const struct ft_dst dsts[], size_t n_dsts,
-           tag_type tags)
-{
-    struct ft_flow *f;
-
-    assert(!flow->reserved);
-    f = xmalloc(sizeof *f);
-    f->tags = tags;
-    f->flow = *flow;
-    f->need_drop = false;
-    f->node.hash = flow_hash(&f->flow, 0);
-    f->dsts = &f->one_dst;
-    ftf_set_dsts(f, dsts, n_dsts);
-    f->last_byte_count = f->byte_count = 0;
-    return f;
-}
-
-void
-ftf_destroy(struct ft_flow *f)
-{
-    if (f) {
-        ftf_set_dsts(f, NULL, 0);
-        free(f);
-    }
-}
-
-void
-ftf_set_dsts(struct ft_flow *f, const struct ft_dst dsts[], size_t n_dsts)
-{
-    if (f->dsts != &f->one_dst) {
-        free(f->dsts);
-    }
-
-    f->n_dsts = n_dsts;
-    if (n_dsts > 1) {
-        f->dsts = xmemdup(dsts, sizeof *f->dsts * n_dsts);
-    } else {
-        f->dsts = &f->one_dst;
-        if (n_dsts) {
-            f->one_dst = *dsts;
-        }
-    }
-}
-\f
-struct ft *
-ft_create(void)
-{
-    struct ft *ft = xcalloc(1, sizeof *ft);
-    hmap_init(&ft->flows);
-    return ft;
-}
-
-void
-ft_destroy(struct ft *ft)
-{
-    if (ft) {
-        struct ft_flow *f, *next;
-
-        HMAP_FOR_EACH_SAFE (f, next, struct ft_flow, node, &ft->flows) {
-            ftf_destroy(f);
-        }
-        hmap_destroy(&ft->flows);
-        free(ft);
-    }
-}
-
-struct ft_flow *
-ft_lookup(const struct ft *ft, const flow_t *target, size_t hash)
-{
-    struct ft_flow *f;
-
-    assert(!target->reserved);
-    HMAP_FOR_EACH_WITH_HASH (f, struct ft_flow, node, hash, &ft->flows) {
-        if (flow_equal(&f->flow, target)) {
-            return f;
-        }
-    }
-    return NULL;
-}
-
-void
-ft_remove(struct ft *ft, struct ft_flow *f)
-{
-    hmap_remove(&ft->flows, &f->node);
-    /* It's the caller's responsible to free 'f', if desired. */
-}
-
-void
-ft_insert(struct ft *ft, struct ft_flow *f)
-{
-    hmap_insert(&ft->flows, &f->node, f->node.hash);
-}
diff --git a/vswitchd/flowtrack.h b/vswitchd/flowtrack.h
deleted file mode 100644 (file)
index c0c40c6..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright (c) 2008, 2009  Nicira Networks
- * 
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * In addition, as a special exception, Nicira Networks gives permission
- * to link the code of its release of vswitchd with the OpenSSL project's
- * "OpenSSL" library (or with modified versions of it that use the same
- * license as the "OpenSSL" library), and distribute the linked
- * executables.  You must obey the GNU General Public License in all
- * respects for all of the code used other than "OpenSSL".  If you modify
- * this file, you may extend this exception to your version of the file,
- * but you are not obligated to do so.  If you do not wish to do so,
- * delete this exception statement from your version.
- */
-
-#ifndef VSWITCHD_FLOWTRACK_H
-#define VSWITCHD_FLOWTRACK_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-#include "flow.h"
-#include "hmap.h"
-#include "tag.h"
-
-struct ofp_action_header;
-
-struct ft_dst {
-    uint16_t vlan;
-    uint16_t dp_ifidx;
-};
-
-static inline bool ftd_equal(const struct ft_dst *, size_t,
-                             const struct ft_dst *, size_t);
-bool ftd_equal_actions(const struct ft_dst *, size_t,
-                       const struct ofp_action_header *, size_t n_oah,
-                       uint16_t flow_vlan);
-void ftd_print(const struct ft_dst *, size_t);
-
-static inline bool
-ftd_equal(const struct ft_dst *a, size_t an,
-          const struct ft_dst *b, size_t bn)
-{
-    return an == bn && !memcmp(a, b, an * sizeof *a);
-}
-
-\f
-struct ft_flow {
-    tag_type tags;
-    struct hmap_node node;
-    flow_t flow;
-    bool need_drop;
-
-    /* Statistics. */
-    uint64_t last_byte_count;
-    uint64_t byte_count;
-
-    /* Actions. */
-    struct ft_dst *dsts;
-    size_t n_dsts;
-    struct ft_dst one_dst;
-};
-
-struct ft_flow *ftf_create(const flow_t *,
-                           const struct ft_dst[], size_t n_dsts,
-                           tag_type tags);
-void ftf_destroy(struct ft_flow *);
-void ftf_set_dsts(struct ft_flow *, const struct ft_dst[], size_t n_dsts);
-\f
-struct ft {
-    struct hmap flows;
-};
-
-struct ft *ft_create(void);
-void ft_destroy(struct ft *);
-void ft_swap(struct ft *, struct ft *);
-struct ft_flow *ft_lookup(const struct ft *, const flow_t *, size_t hash);
-void ft_remove(struct ft *, struct ft_flow *);
-void ft_insert(struct ft *, struct ft_flow *);
-
-#endif /* vswitchd/flowtrack.h */