Stop using vswitch OpenFlow connection to ofproto, by adding ofproto features.
authorBen Pfaff <blp@nicira.com>
Mon, 9 Mar 2009 22:49:35 +0000 (15:49 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 9 Mar 2009 22:49:35 +0000 (15:49 -0700)
secchan/fail-open.c
secchan/in-band.c
secchan/main.c
secchan/ofproto.c
secchan/ofproto.h
vswitchd/automake.mk
vswitchd/bridge.c
vswitchd/stats.c [deleted file]
vswitchd/stats.h [deleted file]

index 90915a33bacfc033647294ad61f7b8a59b63cb73..9f9718cb162ce982a07df06e50c694f4bebbb7fd 100644 (file)
@@ -116,11 +116,11 @@ fail_open_handle_flow_miss(struct fail_open *fo, struct ofproto *ofproto,
     action.output.len = htons(sizeof action);
     if (in_port == out_port || out_port == DROP) {
         /* Set up a flow to drop packets. */
-        ofproto_setup_exact_flow(ofproto, flow, NULL, 0, NULL);
+        ofproto_add_flow(ofproto, flow, NULL, 0, NULL, 0);
     } else if (out_port != FLOOD) {
         /* The output port is known, so add a new flow. */
         action.output.port = htons(out_port);
-        ofproto_setup_exact_flow(ofproto, flow, &action, 1, payload);
+        ofproto_add_flow(ofproto, flow, &action, 1, payload, 0);
     } else {
         /* We don't know that MAC.  Send along the packet without setting up a
          * flow. */
index c5793f08a368eb5ea267fac9b71be9a38bfb75bf..3f5db494fc9eaaecea55cfb2edc1b69cd9ddc080 100644 (file)
@@ -189,11 +189,11 @@ in_band_handle_flow_miss(struct in_band *in_band, struct ofproto *ofproto,
     action.output.len = htons(sizeof action);
     if (in_port == out_port || out_port == DROP) {
         /* Set up a flow to drop packets. */
-        ofproto_setup_exact_flow(ofproto, flow, NULL, 0, NULL);
+        ofproto_add_flow(ofproto, flow, NULL, 0, NULL, 0);
     } else if (out_port != FLOOD) {
         /* The output port is known, so add a new flow. */
         action.output.port = htons(out_port);
-        ofproto_setup_exact_flow(ofproto, flow, &action, 1, payload);
+        ofproto_add_flow(ofproto, flow, &action, 1, payload, 0);
     } else {
         /* We don't know that MAC.  Send along the packet without setting up a
          * flow. */
index f42fab2ac174b56a648aa9d4b58b9fc492f57028..79c62b800d0cffd3d99d1f91891acbe4eb3a8f93 100644 (file)
@@ -156,7 +156,7 @@ main(int argc, char *argv[])
     VLOG_INFO("OpenFlow protocol version 0x%02x", OFP_VERSION);
 
     /* Start OpenFlow processing. */
-    error = ofproto_create(s.dp_name, &ofproto);
+    error = ofproto_create(s.dp_name, NULL, NULL, &ofproto);
     if (error) {
         ofp_fatal(error, "could not initialize openflow switch");
     }
index df5458c967f24384c7ba21a8ae1e17ba9ace9671..e6af97a40e3fdd4d2f62e5eb43ec0af281d90200 100644 (file)
@@ -168,10 +168,16 @@ struct ofproto {
     struct ofconn *controller;
     struct pvconn **listeners;
     size_t n_listeners;
+
+    /* Hooks for vswitchd. */
+    const struct ofhooks *ofhooks;
+    void *aux;
 };
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
+static const struct ofhooks null_ofhooks;
+
 static uint64_t pick_datapath_id(struct dpif *, uint64_t fallback_dpid);
 static uint64_t pick_fallback_dpid(void);
 static void send_packet_in_miss(struct ofpbuf *, void *ofproto);
@@ -191,11 +197,9 @@ static void update_port(struct ofproto *, const char *devname);
 static int init_ports(struct ofproto *);
 static void reinit_ports(struct ofproto *);
 
-static uint16_t odp_port_to_ofp_port(uint16_t odp_port);
-static uint16_t ofp_port_to_odp_port(uint16_t ofp_port);
-
 int
-ofproto_create(const char *datapath, struct ofproto **ofprotop)
+ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
+               struct ofproto **ofprotop)
 {
     struct dpifmon *dpifmon;
     struct ofproto *p;
@@ -266,6 +270,10 @@ ofproto_create(const char *datapath, struct ofproto **ofprotop)
     p->listeners = NULL;
     p->n_listeners = 0;
 
+    /* Initialize hooks. */
+    p->ofhooks = ofhooks ? ofhooks : &null_ofhooks;
+    p->aux = aux;
+
     /* Register switch status category. */
     p->ss_cat = switch_status_register(p->switch_status, "remote",
                                        rconn_status_cb, p->controller->rconn);
@@ -760,9 +768,9 @@ ofproto_send_packet(struct ofproto *p, const flow_t *flow,
 }
 
 void
-ofproto_setup_exact_flow(struct ofproto *p, const flow_t *flow,
-                         const union ofp_action *actions, size_t n_actions,
-                         const struct ofpbuf *packet)
+ofproto_add_flow(struct ofproto *p, const flow_t *flow,
+                 const union ofp_action *actions, size_t n_actions,
+                 const struct ofpbuf *packet, int idle_timeout)
 {
     struct rule *rule, *displaced_rule;
     struct odp_actions odp_actions;
@@ -770,7 +778,7 @@ ofproto_setup_exact_flow(struct ofproto *p, const flow_t *flow,
 
     rule = xmalloc(sizeof *rule);
     cls_rule_from_flow(&rule->cr, flow, 0, UINT16_MAX);
-    rule->idle_timeout = 5;     /* XXX */
+    rule->idle_timeout = idle_timeout ? idle_timeout : 5; /* XXX */
     rule->hard_timeout = 0;     /* XXX */
     rule->used = rule->created = time_msec();
     rule->packet_count = 0;
@@ -803,6 +811,43 @@ ofproto_setup_exact_flow(struct ofproto *p, const flow_t *flow,
     dpif_flow_add(&p->dpif, &odp_flow);
     odp_actions_free(&odp_actions);
 }
+
+void
+ofproto_set_actions(struct ofproto *ofproto, const flow_t *flow,
+                    const union ofp_action *actions, size_t n_actions)
+{
+    struct odp_actions odp_actions;
+    struct rule *rule;
+
+    rule = rule_from_cls_rule(classifier_lookup_exact(&ofproto->cls, flow));
+    if (!rule) {
+        return;
+    }
+
+    free(rule->actions);
+    rule->n_actions = n_actions;
+    rule->actions = xmemdup(actions, n_actions * sizeof *rule->actions);
+
+    rule_make_actions(ofproto, rule, &odp_actions);
+    dpif_flow_set_actions(&ofproto->dpif, flow, odp_actions.actions,
+                          odp_actions.n_actions);
+    odp_actions_free(&odp_actions);
+}
+
+void
+ofproto_delete_flow(struct ofproto *ofproto, const flow_t *flow)
+{
+    struct rule *rule;
+
+    rule = rule_from_cls_rule(classifier_lookup_exact(&ofproto->cls, flow));
+    if (rule) {
+        classifier_remove(&ofproto->cls, &rule->cr);
+        rule_destroy(rule);
+        /* We don't call back to the flow_expired_cb because our caller would
+         * explode, but perhaps we should fix that.  At any rate should we sent
+         * out a netflow message? */
+    }
+}
 \f
 static void
 reinit_ports(struct ofproto *p)
@@ -943,6 +988,9 @@ send_port_status(struct ofproto *p, const struct ofport *ofport,
         hton_ofp_phy_port(&ops->desc);
         queue_tx(b, ofconn);
     }
+    if (p->ofhooks->port_changed_cb) {
+        p->ofhooks->port_changed_cb(reason, &ofport->opp, p->aux);
+    }
 }
 
 static void
@@ -2416,6 +2464,12 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
             return;
         }
 
+        if (p->ofhooks->packet_in_cb
+            && p->ofhooks->packet_in_cb(&flow, &payload, p->aux)) {
+            ofpbuf_delete(packet);
+            return;
+        }
+
         /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */
         port = port_array_get(&p->ports, msg->port);
         if (port) {
@@ -2579,7 +2633,8 @@ send_flow_exp(struct ofproto *p, struct rule *rule,
         queue_tx(buf, prev);
     }
 
-    if (!rule->cr.wc.wildcards && p->netflow) {
+    if (!rule->cr.wc.wildcards
+        && (p->netflow || p->ofhooks->flow_expired_cb)) {
         struct ofexpired expired;
         expired.flow = rule->cr.flow;
         expired.packet_count = rule->packet_count;
@@ -2588,7 +2643,14 @@ send_flow_exp(struct ofproto *p, struct rule *rule,
         expired.created = rule->created;
         expired.tcp_flags = rule->tcp_flags;
         expired.ip_tos = rule->ip_tos;
-        netflow_expire(p->netflow, &expired);
+
+        if (p->netflow) {
+            netflow_expire(p->netflow, &expired);
+        }
+
+        if (p->ofhooks->flow_expired_cb) {
+            p->ofhooks->flow_expired_cb(&expired, p->aux);
+        }
     }
 }
 
index 8a498e2d92d767da8fee311ad3b4469fb73531b5..1940f389f9bc01c86a5597d00c30865d34ae6e8b 100644 (file)
@@ -40,6 +40,7 @@
 #include "flow.h"
 
 struct odp_actions;
+struct ofhooks;
 struct ofproto;
 struct svec;
 
@@ -53,7 +54,8 @@ struct ofexpired {
     uint8_t ip_tos;             /* Last-seen IP type-of-service. */
 };
 
-int ofproto_create(const char *datapath, struct ofproto **ofprotop);
+int ofproto_create(const char *datapath, const struct ofhooks *, void *aux,
+                   struct ofproto **ofprotop);
 void ofproto_destroy(struct ofproto *);
 int ofproto_run(struct ofproto *);
 void ofproto_wait(struct ofproto *);
@@ -92,8 +94,20 @@ void ofproto_get_listeners(const struct ofproto *, struct svec *);
 int ofproto_send_packet(struct ofproto *, const flow_t *,
                         const union ofp_action *, size_t n_actions,
                         const struct ofpbuf *);
-void ofproto_setup_exact_flow(struct ofproto *, const flow_t *,
-                              const union ofp_action *, size_t n_actions,
-                              const struct ofpbuf *);
+void ofproto_add_flow(struct ofproto *, const flow_t *,
+                      const union ofp_action *, size_t n_actions,
+                      const struct ofpbuf *, int idle_timeout);
+void ofproto_set_actions(struct ofproto *, const flow_t *,
+                         const union ofp_action *, size_t n_actions);
+void ofproto_delete_flow(struct ofproto *, const flow_t *);
+
+/* Hooks for vswitchd. */
+struct ofhooks {
+    void (*port_changed_cb)(enum ofp_port_reason, const struct ofp_phy_port *,
+                            void *aux);
+    bool (*packet_in_cb)(const flow_t *, const struct ofpbuf *payload,
+                         void *aux);
+    void (*flow_expired_cb)(const struct ofexpired *, void *aux);
+};
 
 #endif /* ofproto.h */
index 6a263ca84d12c38978d63e09fc2e7aa795a41920..8885f38464c4ce73ee2802cb003beb479ffa91fb 100644 (file)
@@ -10,8 +10,6 @@ vswitchd_vswitchd_SOURCES = \
        vswitchd/bridge.h \
        vswitchd/flowtrack.c \
        vswitchd/flowtrack.h \
-       vswitchd/stats.c \
-       vswitchd/stats.h \
        vswitchd/vswitchd.c
 vswitchd_vswitchd_LDADD = \
        secchan/libsecchan.a \
index d40d6594f2adeb2a6ed11affb135115155012253..38e8550f636cb70ee6107f7adca301ed4e3047c0 100644 (file)
@@ -51,6 +51,7 @@
 #include "list.h"
 #include "mac-learning.h"
 #include "netdev.h"
+#include "odp-util.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
 #include "poll-loop.h"
@@ -59,7 +60,6 @@
 #include "rconn.h"
 #include "secchan/ofproto.h"
 #include "socket-util.h"
-#include "stats.h"
 #include "stp.h"
 #include "svec.h"
 #include "timeval.h"
@@ -152,7 +152,6 @@ struct bridge {
     struct mac_learning *ml;    /* MAC learning table, or null not to learn. */
     int flow_idle_time;         /* Idle time for flows we set up. */
     bool sent_config_request;   /* Successfully sent config request? */
-    bool sent_features_request; /* Successfully sent features request? */
     uint8_t default_ea[ETH_ADDR_LEN]; /* Default MAC. */
 
     /* Support for remote controllers. */
@@ -178,8 +177,6 @@ struct bridge {
     bool flush;
 
     /* Flow statistics gathering. */
-    struct stats_mgr *stats_mgr;
-    struct stats_request *flow_rq; /* Current flow statistics request. */
     time_t next_stats_request;
 
     /* Port mirroring. */
@@ -243,6 +240,9 @@ static void iface_destroy(struct iface *);
 static struct iface *iface_lookup(const struct bridge *, const char *name);
 static struct iface *iface_from_dp_ifidx(const struct bridge *,
                                          uint16_t dp_ifidx);
+
+/* Hooks into ofproto processing. */
+static struct ofhooks bridge_ofhooks;
 \f
 /* Public functions. */
 
@@ -570,7 +570,6 @@ bridge_wait(void)
         if (br->ml) {
             mac_learning_wait(br->ml);
         }
-        stats_mgr_wait(br->stats_mgr);
         flowstats_wait(br);
         bond_wait(br);
         brstp_wait(br);
@@ -618,7 +617,7 @@ bridge_create(const char *name)
         return NULL;
     }
 
-    error = ofproto_create(name, &br->ofproto);
+    error = ofproto_create(name, &bridge_ofhooks, br, &br->ofproto);
     if (error) {
         VLOG_ERR("failed to create OpenFlow switch %s: %s",
                  name, strerror(error));
@@ -633,7 +632,6 @@ bridge_create(const char *name)
     br->ml = mac_learning_create();
     br->flow_idle_time = 5;
     br->sent_config_request = false;
-    br->sent_features_request = false;
     eth_addr_random(br->default_ea);
 
     br->rconn = rconn_create(30, 1);
@@ -644,8 +642,6 @@ bridge_create(const char *name)
     tag_set_init(&br->revalidate_set);
     br->flush = false;
 
-    br->stats_mgr = stats_mgr_create(br->rconn);
-
     list_push_back(&all_bridges, &br->node);
 
     VLOG_INFO("created bridge %s on dp%u", br->name, dpif_id(&br->dpif));
@@ -707,8 +703,6 @@ bridge_destroy(struct bridge *br)
         rconn_packet_counter_destroy(br->txqlen);
         free(br->controller);
         ft_destroy(br->ft);
-        stats_request_destroy(br->flow_rq);
-        stats_mgr_destroy(br->stats_mgr);
         mac_learning_destroy(br->ml);
         port_array_destroy(&br->ifaces);
         free(br->ports);
@@ -764,18 +758,6 @@ send_set_config_request(struct bridge *br)
     }
 }
 
-static void
-send_features_request(struct bridge *br)
-{
-    struct ofp_header *oh;
-    struct ofpbuf *msg;
-
-    oh = make_openflow(sizeof *oh, OFPT_FEATURES_REQUEST, &msg);
-    if (!rconn_send_with_limit(br->rconn, msg, br->txqlen, INT_MAX)) {
-        br->sent_features_request = true;
-    }
-}
-
 static int
 bridge_run_one(struct bridge *br)
 {
@@ -792,9 +774,6 @@ bridge_run_one(struct bridge *br)
         if (!br->sent_config_request) {
             send_set_config_request(br);
         }
-        if (!br->sent_features_request) {
-            send_features_request(br);
-        }
     }
 
     /* Now do the things that may want to revalidate flows. */
@@ -1126,12 +1105,6 @@ bridge_idle_time(const struct bridge *br)
 
 typedef void packet_handler_func(struct bridge *, void *);
 static packet_handler_func process_echo_request;
-static packet_handler_func process_packet_in;
-static packet_handler_func process_flow_expired;
-static packet_handler_func process_stats_reply;
-static packet_handler_func process_error_msg;
-static packet_handler_func process_features_reply;
-static packet_handler_func process_port_status;
 
 static void
 bridge_process_msg(struct bridge *br, struct ofpbuf *msg)
@@ -1141,24 +1114,6 @@ bridge_process_msg(struct bridge *br, struct ofpbuf *msg)
     case OFPT_ECHO_REQUEST:
         process_echo_request(br, msg->data);
         break;
-    case OFPT_PACKET_IN:
-        process_packet_in(br, msg->data);
-        break;
-    case OFPT_FLOW_EXPIRED:
-        process_flow_expired(br, msg->data);
-        break;
-    case OFPT_STATS_REPLY:
-        process_stats_reply(br, msg->data);
-        break;
-    case OFPT_ERROR:
-        process_error_msg(br, msg->data);
-        break;
-    case OFPT_FEATURES_REPLY:
-        process_features_reply(br, msg->data);
-        break;
-    case OFPT_PORT_STATUS:
-        process_port_status(br, msg->data);
-        break;
     default:
         if (VLOG_IS_DBG_ENABLED()) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
@@ -1564,27 +1519,28 @@ put_actions(const struct ft_dst dsts[], size_t n_dsts, uint16_t flow_vlan,
     }
 }
 
-struct received_packet {
-    struct ofpbuf *buf;      /* NULL if no packet data. */
-    uint32_t buffer_id;      /* Host byte order; UINT32_MAX if not buffered. */
-};
-
 static void
 send_packets(struct bridge *br, const flow_t *flow,
-             const struct received_packet *pkt, uint16_t vlan,
+             const struct ofpbuf *pkt, uint16_t vlan,
              const struct port *in_port, const struct port *out_port,
              tag_type tags, bool setup_flow)
 {
     struct ft_dst dsts[DP_MAX_PORTS * (MAX_MIRRORS + 1)];
     size_t actions_len;         /* Estimated length of actions, in bytes. */
     size_t n_dsts;
+    flow_t odp_flow;
 
     n_dsts = compose_dsts(br, flow, vlan, in_port, out_port, dsts, &tags);
     actions_len = (sizeof(struct ofp_action_header) + 2) * n_dsts;
 
+    /* XXX for now everything in bridge.c is still in terms of OFP ports.  In
+     * the long term we should change that (and avoid this awkward copy). */
+    odp_flow = *flow;
+    odp_flow.in_port = ofp_port_to_odp_port(odp_flow.in_port);
+
     if (setup_flow) {
+        enum { NO_OP, ADD_FLOW, SET_ACTIONS } command;
         struct ft_flow *f;
-        int command;
 
         f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
         if (f) {
@@ -1593,7 +1549,7 @@ send_packets(struct bridge *br, const flow_t *flow,
                  * OFPFC_ADD so that we don't reset the idle-timer
                  * countdown for this flow. */
                 ftf_set_dsts(f, dsts, n_dsts);
-                command = OFPFC_MODIFY_STRICT;
+                command = SET_ACTIONS;
             } else {
                 /* Correct flow is already in the flow table, nothing to do.
                  * This should only happen on revalidate, since
@@ -1601,29 +1557,36 @@ send_packets(struct bridge *br, const flow_t *flow,
                  * 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 = -1;
+                command = NO_OP;
             }
             f->tags = tags;
         } else {
             f = ftf_create(flow, dsts, n_dsts, tags);
             ft_insert(br->ft, f);
-            command = OFPFC_ADD;
+            command = ADD_FLOW;
         }
         f->need_drop = false;
 
-        if (command >= 0) {
-            struct ofp_flow_mod *ofm;
-            struct ofpbuf *fbuf;
+        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);
 
-            fbuf = make_add_flow(flow, pkt->buffer_id, bridge_idle_time(br),
-                                 actions_len);
-            ofm = fbuf->data;
-            ofm->command = htons(command);
-            put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), fbuf);
-            queue_tx(br, fbuf);
+            if (command == ADD_FLOW) {
+                ofproto_add_flow(br->ofproto, &odp_flow, abuf.data, n_actions,
+                                 pkt, bridge_idle_time(br));
+                pkt = NULL;     /* Already sent. */
 
-            /* The add_flow message will reset the byte counters. */
-            f->last_byte_count = f->byte_count = 0;
+                /* ofproto_add_flow() will reset the byte counters. */
+                f->last_byte_count = f->byte_count = 0;
+            } else {
+                ofproto_set_actions(br->ofproto, &odp_flow, abuf.data,
+                                    n_actions);
+            }
+            ofpbuf_uninit(&abuf);
         }
     } else {
         struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
@@ -1632,22 +1595,17 @@ send_packets(struct bridge *br, const flow_t *flow,
         }
     }
 
-    if (pkt->buffer_id == UINT32_MAX ? pkt->buf != NULL : !setup_flow) {
-        size_t pkt_size = pkt->buf ? pkt->buf->size : 0;
-        struct ofp_packet_out *opo;
-        struct ofpbuf *pbuf;
+    /* 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;
 
-        pbuf = ofpbuf_new(sizeof *opo + actions_len + pkt_size);
-        opo = put_openflow(sizeof *opo, OFPT_PACKET_OUT, pbuf);
-        opo->buffer_id = htonl(pkt->buffer_id);
-        opo->in_port = flow->in_port;
-        put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), pbuf);
-        opo = pbuf->data;
-        opo->actions_len = htons(pbuf->size - sizeof *opo);
-        if (pkt->buffer_id == UINT32_MAX) {
-            ofpbuf_put(pbuf, pkt->buf->data, pkt->buf->size);
-        }
-        queue_tx(br, pbuf);
+        ofpbuf_init(&abuf, actions_len);
+        put_actions(dsts, n_dsts, ntohs(flow->dl_vlan), &abuf);
+        ofproto_send_packet(br->ofproto, &odp_flow,
+                            abuf.data, abuf.size / sizeof(union ofp_action),
+                            pkt);
+        ofpbuf_uninit(&abuf);
     }
 }
 
@@ -1661,8 +1619,7 @@ is_bcast_arp_reply(const flow_t *flow, const struct ofpbuf *pkt)
 }
 
 static void
-process_flow(struct bridge *br, const flow_t *flow,
-             struct received_packet *pkt)
+process_flow(struct bridge *br, const flow_t *flow, const struct ofpbuf *pkt)
 {
     struct iface *in_iface;
     struct port *in_port;
@@ -1675,7 +1632,7 @@ process_flow(struct bridge *br, const flow_t *flow,
     if (!in_iface) {
         /* No interface?  Something fishy... */
         struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
-        if (pkt->buf || (f && f->need_drop)) {
+        if (pkt || (f && f->need_drop)) {
             /* Odd.  A few possible reasons here:
              *
              * - We deleted an interface but there are still a few packets
@@ -1688,11 +1645,18 @@ process_flow(struct bridge *br, const flow_t *flow,
              *   one of our bridge ports.
              */
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+            flow_t odp_flow;
+
             VLOG_WARN_RL(&rl, "bridge %s: received packet on unknown "
                          "interface %"PRIu16, br->name, flow->in_port); 
 
-            queue_tx(br, make_add_flow(flow, pkt->buffer_id,
-                                       bridge_idle_time(br), 0));
+            /* XXX for now everything in bridge.c is still in terms of OFP
+             * ports.  In the long term we should change that (and avoid this
+             * awkward copy). */
+            odp_flow = *flow;
+            odp_flow.in_port = ofp_port_to_odp_port(odp_flow.in_port);
+            ofproto_add_flow(br->ofproto, &odp_flow, NULL, 0, NULL,
+                             bridge_idle_time(br));
             if (f) {
                 ftf_set_dsts(f, NULL, 0);
                 f->tags = tags;
@@ -1709,8 +1673,19 @@ process_flow(struct bridge *br, const flow_t *flow,
             /* We're revalidating, not receiving a fresh packet.  Most likely,
              * this interface existed and has now been deleted from the
              * datapath.  Drop the flow. */
+            flow_t odp_flow;
+
             assert(f);
-            queue_tx(br, make_del_flow(flow));
+
+            /* XXX for now everything in bridge.c is still in terms of OFP
+             * ports.  In the long term we should change that (and avoid this
+             * awkward copy). */
+            odp_flow = *flow;
+            odp_flow.in_port = ofp_port_to_odp_port(odp_flow.in_port);
+            ofproto_delete_flow(br->ofproto, &odp_flow);
+
+            /* 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. */
@@ -1733,7 +1708,7 @@ process_flow(struct bridge *br, const flow_t *flow,
     if (in_port->vlan >= 0) {
         if (vlan) {
             /* XXX support double tagging? */
-            if (pkt->buf) {
+            if (pkt) {
                 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 "
@@ -1791,7 +1766,7 @@ process_flow(struct bridge *br, const flow_t *flow,
         int out_port_idx;
         bool may_learn;
 
-        if (!pkt->buf) {
+        if (!pkt) {
             /* Don't try to learn from revalidation. */
             may_learn = false;
         } else if (in_port->n_ifaces > 1) {
@@ -1805,7 +1780,7 @@ process_flow(struct bridge *br, const flow_t *flow,
 
             /* 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->buf)) {
+            if (!may_learn && is_bcast_arp_reply(flow, pkt)) {
                 may_learn = true;
             }
         } else {
@@ -1866,47 +1841,7 @@ done:
 static void
 revalidate_flow(struct bridge *br, struct ft_flow *f)
 {
-    struct received_packet pkt;
-    pkt.buf = NULL;
-    pkt.buffer_id = UINT32_MAX;
-    process_flow(br, &f->flow, &pkt);
-}
-
-static void
-process_packet_in(struct bridge *br, void *opi_)
-{
-    struct ofp_packet_in *opi = opi_;
-    struct received_packet pkt;
-    struct ofpbuf buf;
-    flow_t flow;
-
-    if (check_ofp_message_array(&opi->header, OFPT_PACKET_IN,
-                                offsetof(struct ofp_packet_in, data),
-                                1, &buf.size)) {
-        return;
-    }
-    buf.data = opi->data;
-    pkt.buf = &buf;
-    pkt.buffer_id = ntohl(opi->buffer_id);
-    flow_extract(&buf, ntohs(opi->in_port), &flow);
-
-    if (opi->reason == OFPR_NO_MATCH) {
-        /* Delete any existing flow from the flow table.  It must not really be
-         * there (otherwise we wouldn't be getting a packet-in). */
-        struct ft_flow *f = ft_lookup(br->ft, &flow, flow_hash(&flow, 0));
-        if (f) {
-            ft_remove(br->ft, f);
-            ftf_destroy(f);
-        }
-    }
-
-    if (flow.dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE)
-        && eth_addr_equals(flow.dl_dst, stp_eth_addr)) {
-        brstp_receive(br, &flow, &buf);
-        return;
-    }
-
-    process_flow(br, &flow, &pkt);
+    process_flow(br, &f->flow, NULL);
 }
 
 static void
@@ -1916,58 +1851,18 @@ process_echo_request(struct bridge *br, void *rq_)
     queue_tx(br, make_echo_reply(rq));
 }
 
+/* Careful: 'opp' is in host byte order and opp->port_no is an OFP port
+ * number. */
 static void
-process_flow_expired(struct bridge *br, void *ofe_)
-{
-    struct ofp_flow_expired *ofe = ofe_;
-    struct ft_flow *f;
-    flow_t flow;
-
-    if (check_ofp_message(&ofe->header, OFPT_FLOW_EXPIRED, sizeof *ofe)) {
-        return;
-    }
-
-    if (ofe->match.wildcards != htonl(0)) {
-        /* We don't use flows with wildcards, so there's nothing to do. */
-        return;
-    }
-    flow_from_match(&flow, NULL, &ofe->match);
-
-    f = ft_lookup(br->ft, &flow, flow_hash(&flow, 0));
-    if (f) {
-        /* Update statistics. */
-        f->last_byte_count = f->byte_count;
-        f->byte_count = ntohll(ofe->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");
-    }
-}
-
-static void
-process_stats_reply(struct bridge *br, void *osr)
-{
-    stats_mgr_receive_stats_reply(br->stats_mgr, osr);
-}
-
-static void
-process_error_msg(struct bridge *br, void *oem)
-{
-    stats_mgr_receive_error_msg(br->stats_mgr, oem);
-}
-
-static void
-phy_port_changed(struct bridge *br, enum ofp_port_reason reason,
-                 const struct ofp_phy_port *opp)
+bridge_port_changed_ofhook_cb(enum ofp_port_reason reason,
+                              const struct ofp_phy_port *opp,
+                              void *br_)
 {
+    struct bridge *br = br_;
     struct iface *iface;
     struct port *port;
 
-    iface = iface_from_dp_ifidx(br, ntohs(opp->port_no));
+    iface = iface_from_dp_ifidx(br, opp->port_no);
     if (!iface) {
         return;
     }
@@ -1987,39 +1882,77 @@ phy_port_changed(struct bridge *br, enum ofp_port_reason reason,
         bridge_flush(br);
     } else {
         if (port->n_ifaces > 1) {
-            bool up = !(opp->state & htonl(OFPPS_LINK_DOWN));
+            bool up = !(opp->state & OFPPS_LINK_DOWN);
             bond_link_status_update(iface, up);
         }
         memcpy(iface->mac, opp->hw_addr, ETH_ADDR_LEN);
     }
 }
 
-static void
-process_features_reply(struct bridge *br, void *osf_)
+static bool
+bridge_packet_in_ofhook_cb(const flow_t *flow_, const struct ofpbuf *payload,
+                           void *br_)
 {
-    struct ofp_switch_features *osf = osf_;
-    struct ofp_phy_port *pp;
-    size_t n_pp;
+    struct bridge *br = br_;
+    struct ft_flow *f;
+    flow_t flow;
 
-    if (check_ofp_message_array(&osf->header, OFPT_FEATURES_REPLY,
-                                sizeof *osf, sizeof *osf->ports, &n_pp)) {
-        return;
+    /* XXX for now everything in bridge.c is still in terms of OFP ports.  In
+     * the long term we should change that (and avoid this awkward copy). */
+    flow = *flow_;
+    flow.in_port = odp_port_to_ofp_port(flow.in_port);
+
+    /* 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);
     }
-    for (pp = &osf->ports[0]; pp < &osf->ports[n_pp]; pp++) {
-        phy_port_changed(br, OFPPR_MODIFY, pp);
+
+    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;
     }
+
+    process_flow(br, &flow, payload);
+
+    return true;
 }
 
 static void
-process_port_status(struct bridge *br, void *ops_)
+bridge_flow_expired_ofhook_cb(const struct ofexpired *expired, void *br_)
 {
-    struct ofp_port_status *ops = ops_;
+    struct bridge *br = br_;
+    struct ft_flow *f;
+    flow_t flow;
 
-    if (check_ofp_message(&ops->header, OFPT_PORT_STATUS, sizeof *ops)) {
-        return;
+    /* XXX for now everything in bridge.c is still in terms of OFP ports.  In
+     * the long term we should change that (and avoid this awkward copy). */
+    flow = expired->flow;
+    flow.in_port = odp_port_to_ofp_port(flow.in_port);
+
+    f = ft_lookup(br->ft, &flow, flow_hash(&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");
     }
-    phy_port_changed(br, ops->reason, &ops->desc);
 }
+
+static struct ofhooks bridge_ofhooks = {
+    bridge_port_changed_ofhook_cb,
+    bridge_packet_in_ofhook_cb,
+    bridge_flow_expired_ofhook_cb,
+};
 \f
 /* Flow statistics collection. */
 
@@ -2213,100 +2146,64 @@ bond_rebalance(struct bridge *br)
 
 static void
 request_flow_stats(struct bridge *br)
-{
-    struct ofp_flow_stats_request *ofsr;
-    struct ofp_stats_request *osr;
-    struct ofpbuf *msg;
-
-    osr = make_openflow(sizeof *osr + sizeof *ofsr, OFPT_STATS_REQUEST, &msg);
-    osr->type = htons(OFPST_FLOW);
-    osr->flags = htons(0);
-    ofsr = (struct ofp_flow_stats_request *) osr->body;
-    ofsr->match.wildcards = htonl(OFPFW_ALL);
-    ofsr->table_id = 0xff;
-    ofsr->out_port = htons(OFPP_NONE);
-
-    stats_request_destroy(br->flow_rq);
-    br->flow_rq = stats_request_create(br->stats_mgr, msg);
-}
-
-static void
-flowstats_process(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 ofpbuf *msg;
     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;
-    while (stats_request_get_reply(br->flow_rq, &msg)) {
-        struct ofp_stats_reply *osr = msg->data;
-        const struct ofp_flow_stats *fs;
-        struct flow_stats_iterator i;
-
-        for (fs = flow_stats_first(&i, osr); fs; fs = flow_stats_next(&i)) {
-            size_t n_actions = ((ntohs(fs->length)
-                                 - offsetof(struct ofp_flow_stats, actions))
-                                / sizeof(struct ofp_action_header));
-            struct ft_flow *f;
-            flow_t flow;
-            size_t hash;
-
-            if (fs->match.wildcards != htonl(0)) {
-                /* XXX delete flow */
-                continue;
-            }
-            flow_from_match(&flow, NULL, &fs->match);
-            hash = flow_hash(&flow, 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);
 
-            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;
 
-                /* Update statistics. */
-                f->last_byte_count = f->byte_count;
-                f->byte_count = ntohll(fs->byte_count);
-
-                /* Force the flow to be revalidated and replaced if its actions
-                 * aren't what we expect. */
-                if (!ftd_equal_actions(f->dsts, f->n_dsts,
-                                       fs->actions, n_actions,
-                                       ntohs(flow.dl_vlan))) {
-                    ftf_set_dsts(f, &invalid_dst, 1);
-                    f->tags |= flowstats_tag;
-                    n_tagged++;
-                } else {
-                    bond_account_flow(br, f);
+            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 {
-                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 = fs->byte_count;
-                } else {
-                    VLOG_WARN_RL(&rl, "duplicate flow in flow stats reply");
-                }
+                VLOG_WARN_RL(&rl, "duplicate flow in flow stats reply");
             }
         }
-        ofpbuf_delete(msg);
     }
 
     /* Delete all the flows that remain in br->ft, replacing them by the ones
@@ -2328,39 +2225,17 @@ flowstats_process(struct bridge *br)
 static void
 flowstats_run(struct bridge *br)
 {
-    stats_mgr_run(br->stats_mgr);
-    if (br->flow_rq) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
-        switch (stats_request_get_status(br->flow_rq)) {
-        case EAGAIN:
-            return;
-
-        case 0:
-            flowstats_process(br);
-            break;
-
-        default:
-            VLOG_WARN_RL(&rl, "flow stats request returned error: %s",
-                         strerror(stats_request_get_status(br->flow_rq)));
-            br->next_stats_request = time_now() + 1;
-            break;
-        }
-        stats_request_destroy(br->flow_rq);
-        br->flow_rq = NULL;
-    } else {
-        if (rconn_is_connected(br->rconn)
-            && time_now() >= br->next_stats_request) {
-            request_flow_stats(br);
-            br->next_stats_request = time_now() + 10;
-        }
+    if (rconn_is_connected(br->rconn)
+        && time_now() >= br->next_stats_request) {
+        request_flow_stats(br);
+        br->next_stats_request = time_now() + 10;
     }
 }
 
 static void
 flowstats_wait(struct bridge *br)
 {
-    if (!br->flow_rq && rconn_is_connected(br->rconn)) {
+    if (rconn_is_connected(br->rconn)) {
         poll_timer_wait((br->next_stats_request - time_now()) * 1000);
     }
 }
@@ -2591,7 +2466,10 @@ port_update_bonding(struct port *port)
 static void
 iface_create(struct port *port, const char *name)
 {
-    struct iface *iface = xcalloc(1, sizeof *iface);
+    enum netdev_flags flags;
+    struct iface *iface;
+
+    iface = xcalloc(1, sizeof *iface);
     iface->port = port;
     iface->port_ifidx = port->n_ifaces;
     iface->name = xstrdup(name);
@@ -2600,6 +2478,10 @@ iface_create(struct port *port, const char *name)
     iface->enabled = true;
     iface->delay_expires = LLONG_MAX;
 
+    if (!netdev_nodev_get_flags(name, &flags)) {
+        iface->enabled = (flags & NETDEV_UP) != 0;
+    }
+
     if (port->n_ifaces >= port->allocated_ifaces) {
         port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
                                   sizeof *port->ifaces);
@@ -2974,9 +2856,19 @@ brstp_send_bpdu(struct ofpbuf *pkt, int port_no, void *br_)
         VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d with unknown MAC",
                      br->name, port_no);
     } else {
+        union ofp_action action;
         struct eth_header *eth = pkt->l2;
+        flow_t flow;
+
         memcpy(eth->eth_src, iface->mac, ETH_ADDR_LEN);
-        queue_tx(br, make_unbuffered_packet_out(pkt, OFPP_NONE, port_no));
+
+        memset(&action, 0, sizeof action);
+        action.type = htons(OFPAT_OUTPUT);
+        action.output.len = htons(sizeof action);
+        action.output.port = htons(port_no);
+
+        flow_extract(pkt, htons(OFPP_NONE), &flow);
+        ofproto_send_packet(br->ofproto, &flow, &action, 1, pkt);
     }
     ofpbuf_delete(pkt);
 }
diff --git a/vswitchd/stats.c b/vswitchd/stats.c
deleted file mode 100644 (file)
index 26eea8e..0000000
+++ /dev/null
@@ -1,307 +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 "stats.h"
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include "list.h"
-#include "ofpbuf.h"
-#include "openflow/openflow.h"
-#include "poll-loop.h"
-#include "rconn.h"
-#include "timeval.h"
-#include "util.h"
-#include "vconn.h"
-
-#define THIS_MODULE VLM_stats
-#include "vlog.h"
-
-/* XXX when an ongoing stats requests is canceled, might want to wait for the
- * completed replies before sending the next request */
-
-struct stats_mgr {
-    struct stats_request *rq;
-    struct list requests;
-    struct rconn *rconn;
-    unsigned int rconn_seqno;
-    struct rconn_packet_counter *txqlen;
-    time_t timeout;
-};
-
-/* Number of seconds we'll wait for a stats reply before giving up. */
-#define STATS_TIMEOUT 5
-
-struct stats_request {
-    struct stats_mgr *mgr;
-    struct list node;
-    struct ofpbuf *osr;
-    uint32_t xid;
-    uint16_t type;
-    enum {
-        SR_INIT,
-        SR_PARTIAL,
-        SR_DONE
-    } state;
-    int error;
-    struct ofp_queue replies;
-};
-
-static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-
-static void complete_request(struct stats_request *, int error);
-static void send_stats_request(struct stats_mgr *);
-static void cancel_all_requests(struct stats_mgr *, int error);
-\f
-/* Creates and returns a new stats_mgr that sends stats requests on 'rconn'. */
-struct stats_mgr *
-stats_mgr_create(struct rconn *rconn)
-{
-    struct stats_mgr *mgr = xcalloc(1, sizeof *mgr);
-    mgr->rq = NULL;
-    list_init(&mgr->requests);
-    mgr->rconn = rconn;
-    mgr->rconn_seqno = rconn_get_connection_seqno(rconn);
-    mgr->txqlen = rconn_packet_counter_create();
-    return mgr;
-}
-
-/* Destroys 'mgr'.  Careful: the rconn underlying 'mgr' must be destroyed
- * *before* calling this function (because destroying the rconn will update
- * 'mgr->txqlen').
- *
- * stats_requests on 'mgr' are canceled, but not destroyed; the client must
- * destroy them individually with stats_request_destroy(). */
-void
-stats_mgr_destroy(struct stats_mgr *mgr)
-{
-    if (mgr) {
-        rconn_packet_counter_destroy(mgr->txqlen);
-        cancel_all_requests(mgr, ECONNABORTED);
-        free(mgr);
-    }
-}
-
-/* Allows 'mgr' to process 'osr' that was received on 'mgr''s rconn. */
-void
-stats_mgr_receive_stats_reply(struct stats_mgr *mgr,
-                              const struct ofp_stats_reply *osr)
-{
-    struct stats_request *rq = mgr->rq;
-
-    if (!rq || check_ofp_message_array(&osr->header, OFPT_STATS_REPLY,
-                                       sizeof *osr, 1, NULL)) {
-        return;
-    }
-    if (osr->header.xid != rq->xid) {
-        VLOG_DBG_RL(&rl, "stats reply has xid %08"PRIx32" != "
-                    "expected %08"PRIx32, osr->header.xid, rq->xid);
-        return;
-    }
-    if (osr->type != rq->type) {
-        VLOG_WARN_RL(&rl, "stats reply has type %04"PRIx16" != "
-                     "expected %04"PRIx16, osr->type, rq->type);
-        return;
-    }
-
-    queue_push_tail(&rq->replies,
-                    ofpbuf_clone_data(osr, ntohs(osr->header.length)));
-    if (osr->flags & htons(OFPSF_REPLY_MORE)) {
-        rq->state = SR_PARTIAL;
-        mgr->timeout = time_now() + STATS_TIMEOUT;
-    } else {
-        complete_request(rq, 0);
-        send_stats_request(mgr);
-    }
-}
-
-/* Allows 'mgr' to process 'oem' that was received on 'mgr''s rconn. */
-void
-stats_mgr_receive_error_msg(struct stats_mgr *mgr,
-                            const struct ofp_error_msg *oem)
-{
-    struct stats_request *rq = mgr->rq;
-
-    if (!rq
-        || check_ofp_message_array(&oem->header, OFPT_ERROR,
-                                   sizeof *oem, 1, NULL)
-        || oem->header.xid != rq->xid) {
-        return;
-    }
-
-    VLOG_WARN_RL(&rl, "error reply to stats request (%"PRIu16", %"PRIu16")",
-                 ntohs(oem->type), ntohs(oem->code));
-    complete_request(rq, EPROTO);
-    send_stats_request(mgr);
-}
-
-/* Performs internal processing for 'mgr'. */
-void
-stats_mgr_run(struct stats_mgr *mgr)
-{
-    if (mgr->rq && time_now() > mgr->timeout) {
-        VLOG_WARN_RL(&rl, "stats request timed out");
-        complete_request(mgr->rq, ETIMEDOUT);
-        send_stats_request(mgr);
-    }
-}
-
-/* Causes the next call to poll_block() to wake up when stats_mgr_run()
- * should be called on 'mgr'. */
-void
-stats_mgr_wait(struct stats_mgr *mgr)
-{
-    if (mgr->rq) {
-        poll_timer_wait((mgr->timeout - time_now()) * 1000);
-    }
-}
-\f
-/* Creates a new stats_request, adds it to 'mgr', and returns it.  'msg' will
- * be sent as the statistics request. */
-struct stats_request *
-stats_request_create(struct stats_mgr *mgr, struct ofpbuf *msg)
-{
-    struct ofp_stats_request *osr = msg->data;
-    struct stats_request *rq;
-
-    /* Flush out any dead requests if the rconn connected or disconnected, and
-     * update mgr->rconn_seqno so that the request we are about to queue can be
-     * sent. */
-    send_stats_request(mgr);
-
-    /* Queue the request. */
-    rq = xcalloc(1, sizeof *rq);
-    rq->mgr = mgr;
-    list_push_back(&mgr->requests, &rq->node);
-    rq->xid = osr->header.xid;
-    rq->type = osr->type;
-    rq->osr = msg;
-    rq->state = SR_INIT;
-    queue_init(&rq->replies);
-
-    /* Send the request, if possible. */
-    send_stats_request(mgr);
-
-    return rq;
-}
-
-/* Destroys 'rq'. */
-void
-stats_request_destroy(struct stats_request *rq)
-{
-    if (rq) {
-        complete_request(rq, ECANCELED);
-        queue_destroy(&rq->replies);
-        free(rq);
-    }
-}
-
-/* Reports the status of 'rq': 0 if the request completed successfully, EAGAIN
- * if the request is in progress, otherwise a positive errno value if the
- * request completed with an error. */
-int
-stats_request_get_status(const struct stats_request *rq)
-{
-    return rq->state == SR_DONE ? rq->error : EAGAIN;
-}
-
-/*
- * If statistics reply messages remain in the queue in 'rq', stores the first
- * one in '*msg' and returns true.  Otherwise, if no statistics reply messages
- * remain in 'rq''s queue, stores a null pointer in '*msg' and returns false.
- *
- * This function may only be called for 'rq' if stats_request_get_status(rq)
- * returns 0. */
-bool
-stats_request_get_reply(struct stats_request *rq, struct ofpbuf **msg)
-{
-    assert(rq->state == SR_DONE && !rq->error);
-    if (rq->replies.n) {
-        *msg = queue_pop_head(&rq->replies);
-        return true;
-    } else {
-        *msg = NULL;
-        return false;
-    }
-}
-\f
-static void
-complete_request(struct stats_request *rq, int error)
-{
-    struct stats_mgr *mgr = rq->mgr;
-    if (mgr) {
-        if (mgr->rq == rq) {
-            mgr->rq = NULL;
-        } else {
-            list_remove(&rq->node);
-        }
-        rq->mgr = NULL;
-    }
-    if (rq->osr) {
-        ofpbuf_delete(rq->osr);
-        rq->osr = NULL;
-    }
-    rq->state = SR_DONE;
-    rq->error = error;
-}
-
-static void
-cancel_all_requests(struct stats_mgr *mgr, int error)
-{
-    struct stats_request *rq, *next;
-    LIST_FOR_EACH_SAFE (rq, next, struct stats_request, node, &mgr->requests) {
-        complete_request(rq, error);
-    }
-}
-
-static void
-send_stats_request(struct stats_mgr *mgr)
-{
-    if (mgr->rconn_seqno != rconn_get_connection_seqno(mgr->rconn)
-        || !rconn_is_connected(mgr->rconn)) {
-        mgr->rconn_seqno = rconn_get_connection_seqno(mgr->rconn);
-        cancel_all_requests(mgr, ENOTCONN);
-    } else if (!mgr->txqlen->n && !mgr->rq && !list_is_empty(&mgr->requests)) {
-        struct stats_request *rq;
-        int retval;
-
-        rq = mgr->rq = CONTAINER_OF(list_pop_front(&mgr->requests),
-                                  struct stats_request, node);
-        retval = rconn_send(mgr->rconn, rq->osr, mgr->txqlen);
-        if (!retval) {
-            /* rconn_send() consumed the message. */
-            rq->osr = NULL;
-            mgr->timeout = time_now() + STATS_TIMEOUT;
-        } else {
-            /* Sending failed, although it shouldn't have since we already
-             * checked that we were connected.  Odd. */
-            cancel_all_requests(mgr, ENOTCONN);
-        }
-    }
-}
diff --git a/vswitchd/stats.h b/vswitchd/stats.h
deleted file mode 100644 (file)
index ccc006b..0000000
+++ /dev/null
@@ -1,56 +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_STATS_H
-#define VSWITCHD_STATS_H 1
-
-#include <stdbool.h>
-
-struct ofp_error_msg;
-struct ofp_stats_reply;
-struct ofpbuf;
-struct rconn;
-
-/* A stats_mgr managing sending OpenFlow statistics requests over an rconn
- * and receiving the replies. */
-struct stats_mgr *stats_mgr_create(struct rconn *);
-void stats_mgr_destroy(struct stats_mgr *);
-void stats_mgr_receive_stats_reply(struct stats_mgr *,
-                                   const struct ofp_stats_reply *);
-void stats_mgr_receive_error_msg(struct stats_mgr *,
-                                 const struct ofp_error_msg *);
-void stats_mgr_run(struct stats_mgr *);
-void stats_mgr_wait(struct stats_mgr *);
-
-/* A stats_request represents a single OpenFlow statistics request within a
- * stats_mgr. */
-struct stats_request *stats_request_create(struct stats_mgr *,
-                                           struct ofpbuf *);
-void stats_request_destroy(struct stats_request *);
-int stats_request_get_status(const struct stats_request *);
-bool stats_request_get_reply(struct stats_request *, struct ofpbuf **);
-
-#endif /* vswitchd/stats.h */