/Makefile
 /Makefile.in
 /dhparams.c
+/coverage-counters.c
 
        lib/command-line.c \
        lib/command-line.h \
        lib/compiler.h \
+       lib/coverage.c \
+       lib/coverage.h \
+       lib/coverage-counters.c \
+       lib/coverage-counters.h \
        lib/csum.c \
        lib/csum.h \
        lib/daemon.c \
        $(MKDIR_P) $(DESTDIR)$(RUNDIR)
        $(MKDIR_P) $(DESTDIR)$(PKIDIR)
        $(MKDIR_P) $(DESTDIR)$(LOGDIR)
+
+# All the source files that have coverage counters.
+COVERAGE_SOURCES = \
+       lib/dpif.c \
+       lib/flow.c \
+       lib/hmap.c \
+       lib/mac-learning.c \
+       lib/netdev.c \
+       lib/netlink.c \ 
+       lib/odp-util.c \
+       lib/poll-loop.c \
+       lib/process.c \
+       lib/rconn.c \
+       lib/timeval.c \
+       lib/unixctl.c \
+       lib/util.c \
+       lib/vconn.c \
+       secchan/ofproto.c \
+       secchan/pktbuf.c \
+       vswitchd/bridge.c \
+       vswitchd/mgmt.c
+lib/coverage-counters.c: $(COVERAGE_SOURCES) lib/coverage-scan.pl
+       (cd $(srcdir) && $(PERL) lib/coverage-scan.pl $(COVERAGE_SOURCES)) > $@.tmp
+       mv $@.tmp $@
+EXTRA_DIST += lib/coverage-scan.pl
 
--- /dev/null
+/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford Junior
+ * University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#ifndef COVERAGE_COUNTERS_H
+#define COVERAGE_COUNTERS_H 1
+
+#include <stddef.h>
+
+extern struct coverage_counter *coverage_counters[];
+extern size_t coverage_n_counters;
+
+#endif /* coverage.h */
 
--- /dev/null
+# Copyright (c) 2009 The Board of Trustees of The Leland Stanford Junior
+# University
+#
+# We are making the OpenFlow specification and associated documentation
+# (Software) available for public use and benefit with the expectation
+# that others will use, modify and enhance the Software and contribute
+# those enhancements back to the community. However, since we would
+# like to make the Software available for broadest use, with as few
+# restrictions as possible permission is hereby granted, free of
+# charge, to any person obtaining a copy of this Software to deal in
+# the Software under the copyrights without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# The name and trademarks of copyright holder(s) may NOT be used in
+# advertising or publicity pertaining to the Software or any
+# derivatives without specific, written prior permission.
+
+use strict;
+use warnings;
+
+my %counters;
+while (<>) {
+    my ($counter) = /^\s*COVERAGE_(?:INC|ADD)\s*\(\s*([a-zA-Z_][a-zA-Z_0-9]*)/
+      or next;
+    push (@{$counters{$counter}}, "$ARGV:$.");
+} continue {
+    # This magic resets $. from one file to the next.  See "perldoc -f eof".
+    close ARGV if eof;
+}
+
+print <<EOF;
+#include "coverage-counters.h"
+#include <stddef.h>
+#include "coverage.h"
+#include "util.h"
+
+EOF
+
+for my $counter (sort(keys(%counters))) {
+    my $locations = join(', ', @{$counters{$counter}});
+    print <<EOF;
+/* $locations */
+struct coverage_counter ${counter}_count = { "$counter", 0, 0 };
+
+EOF
+}
+print "struct coverage_counter *coverage_counters[] = {\n";
+print "    \&${_}_count,\n" foreach (sort(keys(%counters)));
+print "};\n";
+print "size_t coverage_n_counters = ARRAY_SIZE(coverage_counters);\n";
 
--- /dev/null
+/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford Junior
+ * University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#include <config.h>
+#include "coverage.h"
+#include "coverage-counters.h"
+#include "dynamic-string.h"
+#include "util.h"
+
+#define THIS_MODULE VLM_coverage
+#include "vlog.h"
+
+static unsigned int epoch;
+
+static void
+coverage_log_counter(enum vlog_level level, const struct coverage_counter *c)
+{
+    VLOG(level, "%-24s %5u / %9llu", c->name, c->count, c->count + c->total);
+}
+
+/* Logs the coverage counters at the given vlog 'level'. */
+void
+coverage_log(enum vlog_level level)
+{
+    size_t i;
+    size_t n_never_hit;
+
+    if (!vlog_is_enabled(THIS_MODULE, level)) {
+        return;
+    }
+
+    n_never_hit = 0;
+    VLOG(level, "Event coverage (epoch %u/entire run):", epoch);
+    for (i = 0; i < coverage_n_counters; i++) {
+        struct coverage_counter *c = coverage_counters[i];
+        if (c->count) {
+            coverage_log_counter(level, c);
+        }
+    }
+    for (i = 0; i < coverage_n_counters; i++) {
+        struct coverage_counter *c = coverage_counters[i];
+        if (!c->count) {
+            if (c->total) {
+                coverage_log_counter(level, c);
+            } else {
+                n_never_hit++;
+            }
+        }
+    }
+    VLOG(level, "%zu events never hit", n_never_hit);
+}
+
+/* Advances to the next epoch of coverage, resetting all the counters to 0. */
+void
+coverage_clear(void)
+{
+    size_t i;
+
+    epoch++;
+    for (i = 0; i < coverage_n_counters; i++) {
+        struct coverage_counter *c = coverage_counters[i];
+        c->total += c->count;
+        c->count = 0;
+    }
+}
 
--- /dev/null
+/* Copyright (c) 2009 The Board of Trustees of The Leland Stanford Junior
+ * University
+ *
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
+ */
+
+#ifndef COVERAGE_H
+#define COVERAGE_H 1
+
+/* This file implements a simple form of coverage instrumentation.  Points in
+ * source code that are of interest must be explicitly annotated with
+ * COVERAGE_INC.  The coverage counters may be logged at any time with
+ * coverage_log().
+ *
+ * This form of coverage instrumentation is intended to be so lightweight that
+ * it can be enabled in production builds.  It is obviously not a substitute
+ * for traditional coverage instrumentation with e.g. "gcov", but it is still
+ * a useful debugging tool. */
+
+#include "vlog.h"
+
+/* A coverage counter. */
+struct coverage_counter {
+    const char *name;           /* Textual name. */
+    unsigned int count;         /* Count within the current epoch. */
+    unsigned long long int total; /* Total count over all epochs. */
+};
+
+/* Increments the counter with the given NAME.  Coverage counters need not be
+ * declared explicitly, but when you add the first coverage counter to a given
+ * file, you must also add that file to COVERAGE_SOURCES in lib/automake.mk. */
+#define COVERAGE_INC(NAME)                              \
+    do {                                                \
+        extern struct coverage_counter NAME##_count;    \
+        NAME##_count.count++;                           \
+    } while (0)
+
+/* Adds AMOUNT to the coverage counter with the given NAME. */
+#define COVERAGE_ADD(NAME, AMOUNT)                      \
+    do {                                                \
+        extern struct coverage_counter NAME##_count;    \
+        NAME##_count.count += AMOUNT;                   \
+    } while (0)
+
+void coverage_log(enum vlog_level);
+void coverage_clear(void);
+
+#endif /* coverage.h */
 
 #include <sys/sysmacros.h>
 #include <unistd.h>
 
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "flow.h"
 #include "netlink.h"
 int
 dpif_delete(struct dpif *dpif)
 {
+    COVERAGE_INC(dpif_destroy);
     return do_ioctl(dpif, ODP_DP_DESTROY, "ODP_DP_DESTROY", NULL);
 }
 
     unsigned int i;
     int error;
 
+    COVERAGE_INC(dpif_purge);
+
     error = dpif_get_dp_stats(dpif, &stats);
     if (error) {
         return error;
 {
     struct odp_port port;
 
+    COVERAGE_INC(dpif_port_add);
     memset(&port, 0, sizeof port);
     strncpy(port.devname, devname, sizeof port.devname);
     port.port = port_no;
 dpif_port_del(struct dpif *dpif, uint16_t port_no)
 {
     int tmp = port_no;
+    COVERAGE_INC(dpif_port_del);
     return do_ioctl(dpif, ODP_PORT_DEL, "ODP_PORT_DEL", &tmp);
 }
 
 {
     struct odp_port_group pg;
 
+    COVERAGE_INC(dpif_port_group_set);
     assert(n_ports <= UINT16_MAX);
     pg.group = group;
     pg.ports = (uint16_t *) ports;
 int
 dpif_flow_flush(struct dpif *dpif)
 {
+    COVERAGE_INC(dpif_flow_flush);
     return do_ioctl(dpif, ODP_FLOW_FLUSH, "ODP_FLOW_FLUSH", NULL);
 }
 
 dpif_flow_put(struct dpif *dpif, struct odp_flow_put *put)
 {
     int error = do_ioctl(dpif, ODP_FLOW_PUT, NULL, put);
+    COVERAGE_INC(dpif_flow_put);
     if (should_log_flow_message(error)) {
         struct ds operation = DS_EMPTY_INITIALIZER;
         ds_put_cstr(&operation, "put");
 int
 dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
 {
+    COVERAGE_INC(dpif_flow_del);
     check_rw_odp_flow(flow);
     memset(&flow->stats, 0, sizeof flow->stats);
     return do_flow_ioctl(dpif, ODP_FLOW_DEL, flow, "delete flow", true);
 int
 dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
 {
+    COVERAGE_INC(dpif_flow_query);
     check_rw_odp_flow(flow);
     memset(&flow->stats, 0, sizeof flow->stats);
     return do_flow_ioctl(dpif, ODP_FLOW_GET, flow, "get flow", true);
     struct odp_flowvec fv;
     size_t i;
 
+    COVERAGE_ADD(dpif_flow_query_multiple, n);
     fv.flows = flows;
     fv.n_flows = n;
     for (i = 0; i < n; i++) {
     uint32_t i;
     int error;
 
+    COVERAGE_INC(dpif_flow_query_list);
     fv.flows = flows;
     fv.n_flows = n;
     if (RUNNING_ON_VALGRIND) {
         VLOG_WARN_RL(&error_rl, "dp%u: flow list failed (%s)",
                      dpif->minor, strerror(error));
     } else {
+        COVERAGE_ADD(dpif_flow_query_list_n, fv.n_flows);
         *n_out = fv.n_flows;
         VLOG_DBG_RL(&dpmsg_rl, "dp%u: listed %zu flows", dpif->minor, *n_out);
     }
 {
     int error;
 
+    COVERAGE_INC(dpif_execute);
     if (n_actions > 0) {
         struct odp_execute execute;
         memset(&execute, 0, sizeof execute);
 int
 dpif_snat_add_port(struct dpif *dpif, const struct odp_snat_config *osc)
 {
+    COVERAGE_INC(dpif_snat_add_port);
     return do_ioctl(dpif, ODP_SNAT_ADD_PORT, "ODP_SNAT_ADD_PORT", osc);
 }
 
 dpif_snat_del_port(struct dpif *dpif, uint16_t port)
 {
     int tmp = port;
+    COVERAGE_INC(dpif_snat_del_port);
     return do_ioctl(dpif, ODP_SNAT_DEL_PORT, "ODP_SNAT_DEL_PORT", &tmp);
 }
 
                 free(s);
             }
             *bufp = buf;
+            COVERAGE_INC(dpif_recv);
             return 0;
         } else {
             VLOG_WARN_RL(&error_rl, "dp%u: discarding message truncated "
             if (!for_us) {
                 /* Not for us, try again. */
                 ofpbuf_delete(buf);
+                COVERAGE_INC(dpifmon_poll_false_wakeup);
                 goto again;
             }
+            COVERAGE_INC(dpifmon_poll_changed);
             *devnamep = xstrdup(devname);
         }
         ofpbuf_delete(buf);
 
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <string.h>
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "hash.h"
 #include "ofpbuf.h"
     struct eth_header *eth;
     int retval = 0;
 
+    COVERAGE_INC(flow_extract);
+
     memset(flow, 0, sizeof *flow);
     flow->dl_vlan = htons(OFP_VLAN_NONE);
     flow->in_port = in_port;
 
-/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
  * Junior University
  *
  * We are making the OpenFlow specification and associated documentation
 #include "hmap.h"
 #include <assert.h>
 #include <stdint.h>
+#include "coverage.h"
 #include "util.h"
 
 /* Initializes 'hmap' as an empty hash table. */
     }
     for (i = 0; i <= hmap->mask; i++) {
         struct hmap_node *node, *next;
+        int count = 0;
         for (node = hmap->buckets[i]; node; node = next) {
             next = node->next;
             hmap_insert_fast(&tmp, node, node->hash);
+            count++;
+        }
+        if (count > 5) {
+            COVERAGE_INC(hmap_pathological);
         }
     }
     hmap_swap(hmap, &tmp);
 {
     size_t new_mask = calc_mask(hmap->n);
     if (new_mask > hmap->mask) {
+        COVERAGE_INC(hmap_expand);
         resize(hmap, new_mask);
     }
 }
 {
     size_t new_mask = calc_mask(hmap->n);
     if (new_mask < hmap->mask) {
+        COVERAGE_INC(hmap_shrink);
         resize(hmap, new_mask);
     }
 }
 {
     size_t new_mask = calc_mask(n);
     if (new_mask > hmap->mask) {
+        COVERAGE_INC(hmap_reserve);
         resize(hmap, new_mask);
     }
 }
 
 #include <inttypes.h>
 #include <stdlib.h>
 
+#include "coverage.h"
 #include "hash.h"
 #include "list.h"
 #include "poll-loop.h"
         tag_type old_tag = e->tag;
         e->port = src_port;
         e->tag = tag_create_random();
+        COVERAGE_INC(mac_learning_learned);
         return old_tag;
     }
     return 0;
 {
     struct mac_entry *e;
     while (get_lru(ml, &e) && time_now() >= e->expires) {
+        COVERAGE_INC(mac_learning_expired);
         if (set) {
             tag_set_add(set, e->tag);
         }
 
 #include <string.h>
 #include <unistd.h>
 
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "fatal-signal.h"
 #include "list.h"
     ifr.ifr_data = (caddr_t) ecmd;
 
     ecmd->cmd = cmd;
+    COVERAGE_INC(netdev_ethtool);
     if (ioctl(netdev->netdev_fd, SIOCETHTOOL, &ifr) == 0) {
         return 0;
     } else {
 
     init_netdev();
     *netdev_ = NULL;
+    COVERAGE_INC(netdev_open);
 
     /* Create raw socket. */
     netdev_fd = socket(PF_PACKET, SOCK_RAW,
         }
         return errno;
     } else {
+        COVERAGE_INC(netdev_received);
         buffer->size += n_bytes;
 
         /* When the kernel internally sends out an Ethernet frame on an
                      (int) n_bytes, buffer->size, netdev->name);
         return EMSGSIZE;
     } else {
+        COVERAGE_INC(netdev_sent);
         return 0;
     }
 }
 
     strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
     ifr.ifr_addr.sa_family = AF_INET;
+    COVERAGE_INC(netdev_get_in4);
     if (ioctl(af_inet_sock, SIOCGIFADDR, &ifr) == 0) {
         struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
         ip = sin->sin_addr;
 
     strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
     make_in4_sockaddr(&ifr.ifr_addr, addr);
+    COVERAGE_INC(netdev_set_in4);
     error = ioctl(sock, ioctl_nr, &ifr) < 0 ? errno : 0;
     if (error) {
         VLOG_WARN("ioctl(%s): %s", ioctl_name, strerror(error));
     make_in4_sockaddr(&rt.rt_gateway, router);
     make_in4_sockaddr(&rt.rt_genmask, any);
     rt.rt_flags = RTF_UP | RTF_GATEWAY;
+    COVERAGE_INC(netdev_add_router);
     error = ioctl(af_inet_sock, SIOCADDRT, &rt) < 0 ? errno : 0;
     if (error) {
         VLOG_WARN("ioctl(SIOCADDRT): %s", strerror(error));
     r.arp_ha.sa_family = ARPHRD_ETHER;
     r.arp_flags = 0;
     strncpy(r.arp_dev, netdev->name, sizeof r.arp_dev);
+    COVERAGE_INC(netdev_arp_lookup);
     retval = ioctl(af_inet_sock, SIOCGARP, &r) < 0 ? errno : 0;
     if (!retval) {
         memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN);
 {
     int error;
 
+    COVERAGE_INC(netdev_get_stats);
     if (use_netlink_stats) {
         int ifindex;
 
 
     init_netdev();
 
+    COVERAGE_INC(netdev_set_policing);
     if (kbits_rate) {
         if (!kbits_burst) {
             /* Default to 10 kilobits if not specified. */
     int error;
     char *fn;
 
+    COVERAGE_INC(netdev_get_vlan_vid);
     fn = xasprintf("/proc/net/vlan/%s", netdev_name);
     stream = fopen(fn, "r");
     if (!stream) {
 
     /* Get current flags. */
     strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
+    COVERAGE_INC(netdev_get_flags);
     if (ioctl(netdev->netdev_fd, SIOCGIFFLAGS, &ifr) < 0) {
         return errno;
     }
     if ((ifr.ifr_flags ^ netdev->save_flags) & restore_flags) {
         ifr.ifr_flags &= ~restore_flags;
         ifr.ifr_flags |= netdev->save_flags & restore_flags;
+        COVERAGE_INC(netdev_set_flags);
         if (ioctl(netdev->netdev_fd, SIOCSIFFLAGS, &ifr) < 0) {
             return errno;
         }
 {
     struct ifreq ifr;
     strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
+    COVERAGE_INC(netdev_get_flags);
     if (ioctl(af_inet_sock, SIOCGIFFLAGS, &ifr) < 0) {
         VLOG_ERR("ioctl(SIOCGIFFLAGS) on %s device failed: %s",
                  netdev_name, strerror(errno));
     struct ifreq ifr;
     strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_flags = flags;
+    COVERAGE_INC(netdev_set_flags);
     if (ioctl(af_inet_sock, SIOCSIFFLAGS, &ifr) < 0) {
         VLOG_ERR("ioctl(SIOCSIFFLAGS) on %s device failed: %s",
                  netdev_name, strerror(errno));
     struct ifreq ifr;
 
     strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
+    COVERAGE_INC(netdev_get_ifindex);
     if (ioctl(af_inet_sock, SIOCGIFINDEX, &ifr) < 0) {
         VLOG_WARN_RL(&rl, "ioctl(SIOCGIFINDEX) on %s device failed: %s",
                      netdev_name, strerror(errno));
 
     memset(&ifr, 0, sizeof ifr);
     strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
+    COVERAGE_INC(netdev_get_hwaddr);
     if (ioctl(af_inet_sock, SIOCGIFHWADDR, &ifr) < 0) {
         VLOG_ERR("ioctl(SIOCGIFHWADDR) on %s device failed: %s",
                  netdev_name, strerror(errno));
     strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
     ifr.ifr_hwaddr.sa_family = hwaddr_family;
     memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN);
+    COVERAGE_INC(netdev_set_hwaddr);
     if (ioctl(af_inet_sock, SIOCSIFHWADDR, &ifr) < 0) {
         VLOG_ERR("ioctl(SIOCSIFHWADDR) on %s device failed: %s",
                  netdev_name, strerror(errno));
 
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "netlink-protocol.h"
 #include "ofpbuf.h"
         error = retval < 0 ? errno : 0;
     } while (error == EINTR);
     log_nlmsg(__func__, error, msg->data, msg->size);
+    if (!error) {
+        COVERAGE_INC(netlink_sent);
+    }
     return error;
 }
 
     struct msghdr msg;
     int error;
 
+    COVERAGE_INC(netlink_send);
     memset(&msg, 0, sizeof msg);
     msg.msg_iov = (struct iovec *) iov;
     msg.msg_iovlen = n_iov;
     } while (error == EINTR);
     if (error != EAGAIN) {
         log_nlmsg(__func__, error, iov[0].iov_base, iov[0].iov_len);
+        if (!error) {
+            COVERAGE_INC(netlink_sent);
+        }
     }
     return error;
 }
         return errno;
     }
     if (msg.msg_flags & MSG_TRUNC) {
+        COVERAGE_INC(netlink_recv_retry);
         bufsize *= 2;
         ofpbuf_reinit(buf, bufsize);
         goto try_again;
              * was dropped.  We have to pass this along to the caller in case
              * it wants to retry a request.  So kill the buffer, which we can
              * re-read next time. */
+            COVERAGE_INC(netlink_overflow);
             ofpbuf_delete(buf);
             return ENOBUFS;
         } else {
     }
     *bufp = buf;
     log_nlmsg(__func__, 0, buf->data, buf->size);
+    COVERAGE_INC(netlink_received);
     return 0;
 }
 
     retval = nl_sock_recv(sock, &reply, true);
     if (retval) {
         if (retval == ENOBUFS) {
+            COVERAGE_INC(netlink_overflow);
             VLOG_DBG_RL(&rl, "receive buffer overflow, resending request");
             goto send;
         } else {
 
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "flow.h"
 #include "packets.h"
     if (actions->n_actions < MAX_ODP_ACTIONS) {
         a = &actions->actions[actions->n_actions++];
     } else {
+        COVERAGE_INC(odp_overflow);
         actions->n_actions = MAX_ODP_ACTIONS + 1;
         a = &actions->actions[MAX_ODP_ACTIONS - 1];
     }
 
 #include <stdlib.h>
 #include <string.h>
 #include "backtrace.h"
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "list.h"
 #include "timeval.h"
 struct poll_waiter *
 poll_fd_wait(int fd, short int events)
 {
+    COVERAGE_INC(poll_fd_wait);
     return new_waiter(fd, events);
 }
 
         n_pollfds++;
     }
 
+    if (!timeout) {
+        COVERAGE_INC(poll_zero_timeout);
+    }
     retval = time_poll(pollfds, n_pollfds, timeout);
     if (retval < 0) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "list.h"
 #include "poll-loop.h"
 
     *pp = NULL;
     process_init();
+    COVERAGE_INC(process_start);
 
     if (VLOG_IS_DBG_ENABLED()) {
         char *args = process_escape_args(argv);
     struct process *p;
     int retval;
 
+    COVERAGE_INC(process_run);
     retval = process_start(argv, keep_fds, n_keep_fds, null_fds, n_null_fds,
                            &p);
     if (retval) {
 {
     struct process *p;
 
+    COVERAGE_INC(process_sigchld);
     LIST_FOR_EACH (p, struct process, node, &all_processes) {
         if (!p->exited) {
             int retval, status;
 
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include "coverage.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
 #include "poll-loop.h"
            struct rconn_packet_counter *counter)
 {
     if (rconn_is_connected(rc)) {
+        COVERAGE_INC(rconn_queued);
         copy_to_monitor(rc, b);
         b->private = counter;
         if (counter) {
     int retval;
     retval = counter->n >= queue_limit ? EAGAIN : rconn_send(rc, b, counter);
     if (retval) {
+        COVERAGE_INC(rconn_overflow);
         ofpbuf_delete(b);
     }
     return retval;
         }
         return retval;
     }
+    COVERAGE_INC(rconn_sent);
     rc->packets_sent++;
     if (counter) {
         rconn_packet_counter_dec(counter);
         if (counter) {
             rconn_packet_counter_dec(counter);
         }
+        COVERAGE_INC(rconn_discarded);
         ofpbuf_delete(b);
     }
     poll_immediate_wake();
 
 #include <signal.h>
 #include <string.h>
 #include <sys/time.h>
+#include "coverage.h"
 #include "fatal-signal.h"
 #include "util.h"
 
 
     time_refresh();
     log_poll_interval(last_wakeup);
+    coverage_clear();
     start = time_msec();
     blocked = false;
     for (;;) {
                   "the weighted mean interval %u ms (%u samples)",
                   (interval + 8) / 16, interval / mean_interval,
                   (mean_interval + 8) / 16, n_samples);
+        coverage_log(VLL_WARN);
     }
 
     /* Update exponentially weighted moving average.  With these parameters, a
 
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include "coverage.h"
 #include "dirs.h"
 #include "dynamic-string.h"
 #include "fatal-signal.h"
 {
     struct ds *out = &conn->out;
 
+    COVERAGE_INC(unixctl_replied);
     assert(conn->state == S_PROCESS);
     conn->state = S_SEND;
     conn->out_pos = 0;
     size_t name_len;
     char *name, *args;
 
+    COVERAGE_INC(unixctl_received);
     conn->state = S_PROCESS;
 
     name = s;
 
-/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
  * Junior University
  * 
  * We are making the OpenFlow specification and associated documentation
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "coverage.h"
 
 const char *program_name;
 
 xcalloc(size_t count, size_t size) 
 {
     void *p = count && size ? calloc(count, size) : malloc(1);
+    COVERAGE_INC(util_xalloc);
     if (p == NULL) {
         out_of_memory();
     }
 xmalloc(size_t size) 
 {
     void *p = malloc(size ? size : 1);
+    COVERAGE_INC(util_xalloc);
     if (p == NULL) {
         out_of_memory();
     }
 xrealloc(void *p, size_t size) 
 {
     p = realloc(p, size ? size : 1);
+    COVERAGE_INC(util_xalloc);
     if (p == NULL) {
         out_of_memory();
     }
 
 #include <poll.h>
 #include <stdlib.h>
 #include <string.h>
+#include "coverage.h"
 #include "dynamic-string.h"
 #include "flow.h"
 #include "ofp-print.h"
     size_t prefix_len;
     size_t i;
 
+    COVERAGE_INC(vconn_open);
     check_vconn_classes();
 
     *vconnp = NULL;
     if (!retval) {
         struct ofp_header *oh;
 
+        COVERAGE_INC(vconn_received);
         if (VLOG_IS_DBG_ENABLED()) {
             char *s = ofp_to_string((*msgp)->data, (*msgp)->size, 1);
             VLOG_DBG_RL(&ofmsg_rl, "%s: received: %s", vconn->name, s);
     assert(msg->size >= sizeof(struct ofp_header));
     assert(((struct ofp_header *) msg->data)->length == htons(msg->size));
     if (!VLOG_IS_DBG_ENABLED()) {
+        COVERAGE_INC(vconn_sent);
         retval = (vconn->class->send)(vconn, msg);
     } else {
         char *s = ofp_to_string(msg->data, msg->size, 1);
 
 VLOG_MODULE(chain)
 VLOG_MODULE(cfg)
 VLOG_MODULE(controller)
+VLOG_MODULE(coverage)
 VLOG_MODULE(ctlpath)
 VLOG_MODULE(daemon)
 VLOG_MODULE(datapath)
 
 #include <stdbool.h>
 #include <stdlib.h>
 #include "classifier.h"
+#include "coverage.h"
 #include "discovery.h"
 #include "dpif.h"
 #include "executer.h"
     }
 
     if (time_msec() >= p->next_expiration) {
+        COVERAGE_INC(ofproto_expiration);
         p->next_expiration = time_msec() + 1000;
         update_used(p);
 
         cbdata.revalidate_subrules = p->need_revalidate;
         cbdata.revalidate_set = p->revalidate_set;
         tag_set_init(&p->revalidate_set);
+        COVERAGE_INC(ofproto_revalidate);
         classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_cb, &cbdata);
         p->need_revalidate = false;
     }
 void
 ofproto_flush_flows(struct ofproto *ofproto)
 {
+    COVERAGE_INC(ofproto_flush);
     classifier_for_each(&ofproto->cls, CLS_INC_ALL, destroy_rule, ofproto);
     dpif_flow_flush(&ofproto->dpif);
     if (ofproto->in_band) {
     struct ofport *ofport;
     int error;
 
+    COVERAGE_INC(ofproto_update_port);
     ofport = shash_find_data(&p->port_by_name, devname);
     error = dpif_port_query_by_name(&p->dpif, devname, &odp_port);
     if (!error) {
     rconn_run_wait(ofconn->rconn);
     if (rconn_packet_counter_read (ofconn->reply_counter) < OFCONN_REPLY_MAX) {
         rconn_recv_wait(ofconn->rconn);
+    } else {
+        COVERAGE_INC(ofproto_ofconn_stuck);
     }
 }
 \f
     /* Install the rule in the datapath only after sending the packet, to
      * avoid packet reordering.  */
     if (rule->cr.wc.wildcards) {
+        COVERAGE_INC(ofproto_add_wc_flow);
         p->need_revalidate = true;
     } else {
         rule_install(p, rule, displaced_rule);
 {
     struct rule *subrule = rule_create(rule, NULL, 0,
                                        rule->idle_timeout, rule->hard_timeout);
+    COVERAGE_INC(ofproto_subrule_create);
     cls_rule_from_flow(&subrule->cr, flow, 0,
                        (rule->cr.priority <= UINT16_MAX ? UINT16_MAX
                         : rule->cr.priority));
 rule_remove(struct ofproto *ofproto, struct rule *rule)
 {
     if (rule->cr.wc.wildcards) {
+        COVERAGE_INC(ofproto_del_wc_flow);
         ofproto->need_revalidate = true;
     } else {
         rule_uninstall(ofproto, rule);
     actions_len = a.n_actions * sizeof *a.actions;
     if (rule->n_odp_actions != a.n_actions
         || memcmp(rule->odp_actions, a.actions, actions_len)) {
+        COVERAGE_INC(ofproto_odp_unchanged);
         free(rule->odp_actions);
         rule->n_odp_actions = a.n_actions;
         rule->odp_actions = xmemdup(a.actions, actions_len);
 {
     if (rule->installed) {
         struct odp_flow_put put;
+        COVERAGE_INC(ofproto_dp_missed);
         do_put_flow(ofproto, rule, ODPPF_CREATE | ODPPF_MODIFY, &put);
     } else {
         rule_install(ofproto, rule, NULL);
         return;
     }
 
+    COVERAGE_INC(ofproto_error);
     oem = make_openflow_xid(len + sizeof *oem, OFPT_ERROR,
                             oh ? oh->xid : 0, &buf);
     oem->type = htons((unsigned int) error >> 16);
         && rule->super
         && ofproto->need_revalidate
         && !revalidate_rule(ofproto, rule)) {
+        COVERAGE_INC(ofproto_invalidated);
         return NULL;
     }
 
         if (!ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->packet,
                                               ctx->out, ctx->tags,
                                               ctx->ofproto->aux)) {
+            COVERAGE_INC(ofproto_uninstallable);
             ctx->may_setup_flow = false;
         }
         break;
 {
     tag_type no_tags = 0;
     struct action_xlate_ctx ctx;
+    COVERAGE_INC(ofproto_ofp2odp);
     odp_actions_init(out);
     ctx.flow = flow;
     ctx.recurse = 0;
     }
     opo = (struct ofp_packet_out *) oh;
 
+    COVERAGE_INC(ofproto_packet_out);
     if (opo->buffer_id != htonl(UINT32_MAX)) {
         error = pktbuf_retrieve(ofconn->pktbuf, ntohl(opo->buffer_id),
                                 &buffer, &in_port);
     }
 #define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | OFPPC_NO_FWD)
     if (mask & REVALIDATE_BITS) {
+        COVERAGE_INC(ofproto_costly_flags);
         port->opp.config ^= mask & REVALIDATE_BITS;
         p->need_revalidate = true;
     }
     }
     fsr = (struct ofp_flow_stats_request *) osr->body;
 
+    COVERAGE_INC(ofproto_flows_req);
     cbdata.ofproto = p;
     cbdata.ofconn = ofconn;
     cbdata.out_port = fsr->out_port;
     }
     asr = (struct ofp_aggregate_stats_request *) osr->body;
 
+    COVERAGE_INC(ofproto_agg_request);
     cbdata.ofproto = p;
     cbdata.out_port = asr->out_port;
     cbdata.packet_count = 0;
         rule->n_actions = n_actions;
 
         if (rule->cr.wc.wildcards) {
+            COVERAGE_INC(ofproto_mod_wc_flow);
             p->need_revalidate = true;
         } else {
             rule_update_actions(p, rule);
     struct ofp_header *oh = ofp_msg->data;
     int error;
 
+    COVERAGE_INC(ofproto_recv_openflow);
     switch (oh->type) {
     case OFPT_ECHO_REQUEST:
         error = handle_echo_request(ofconn, oh);
 
     /* Handle controller actions. */
     if (msg->type == _ODPL_ACTION_NR) {
+        COVERAGE_INC(ofproto_ctlr_action);
         pinsched_send(p->action_sched, in_port, packet,
                       send_packet_in_action, p);
         return;
         struct ofport *port = port_array_get(&p->ports, msg->port);
         if (port) {
             if (port->opp.config & OFPPC_NO_PACKET_IN) {
+                COVERAGE_INC(ofproto_no_packet_in);
                 /* XXX install 'drop' flow entry */
                 ofpbuf_delete(packet);
                 return;
             VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, msg->port);
         }
 
+        COVERAGE_INC(ofproto_packet_in);
         pinsched_send(p->miss_sched, in_port, packet, send_packet_in_miss, p);
         return;
     }
 {
     const flow_t *flow = &rule->cr.flow;
 
+    COVERAGE_INC(ofproto_revalidate_rule);
     if (rule->super) {
         struct rule *super;
         super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow));
             rule_remove(p, rule);
             return false;
         } else if (super != rule->super) {
+            COVERAGE_INC(ofproto_revalidate_moved);
             list_remove(&rule->list);
             list_push_back(&super->list, &rule->list);
             rule->super = super;
         return;
     }
 
+    COVERAGE_INC(ofproto_expired);
     if (rule->cr.wc.wildcards) {
         /* Update stats.  (This code will be a no-op if the rule expired
          * due to an idle timeout, because in that case the rule has no
         rule = rule_from_cls_rule(
             classifier_find_rule_exactly(&p->cls, &f->key, 0, UINT16_MAX));
         if (!rule || !rule->installed) {
+            COVERAGE_INC(ofproto_unexpected_rule);
             dpif_flow_del(&p->dpif, f);
             continue;
         }
 
 #include "pktbuf.h"
 #include <inttypes.h>
 #include <stdlib.h>
+#include "coverage.h"
 #include "ofpbuf.h"
 #include "timeval.h"
 #include "util.h"
             *bufferp = buffer;
             *in_port = p->in_port;
             p->buffer = NULL;
+            COVERAGE_INC(pktbuf_retrieved);
             return 0;
         } else {
+            COVERAGE_INC(pktbuf_reuse_error);
             VLOG_WARN_RL(&rl, "attempt to reuse buffer %08"PRIx32, id);
             error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY);
         }
     } else {
+        COVERAGE_INC(pktbuf_bad_cookie);
         VLOG_WARN_RL(&rl, "cookie mismatch: %08"PRIx32" != %08"PRIx32,
                      id, (id & PKTBUF_MASK) | (p->cookie << PKTBUF_BITS));
         error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
 
 #include <unistd.h>
 #include "bitmap.h"
 #include "cfg.h"
+#include "coverage.h"
 #include "dirs.h"
 #include "dpif.h"
 #include "flow.h"
     struct bridge *br, *next;
     size_t i, j;
 
+    COVERAGE_INC(bridge_reconfigure);
+
     /* Collect old bridges. */
     svec_init(&old_br);
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
 static void
 bridge_flush(struct bridge *br)
 {
+    COVERAGE_INC(bridge_flush);
     br->flush = true;
     if (br->ml) {
         mac_learning_flush(br->ml);
     }
 #endif
 
+    COVERAGE_INC(bridge_process_flow);
     return process_flow(br, flow, packet, actions, tags);
 }
 
 
 
 #include "bridge.h"
 #include "cfg.h"
+#include "coverage.h"
 #include "list.h"
 #include "mgmt.h"
 #include "openflow/nicira-ext.h"
     struct ofp_header *oh;
     size_t min_size;
 
+    COVERAGE_INC(mgmt_received);
+
     /* Check encapsulated length. */
     oh = (struct ofp_header *) msg;
     if (ntohs(oh->length) > length) {