netdev: New function netdev_get_stats().
authorBen Pfaff <blp@nicira.com>
Mon, 2 Mar 2009 20:41:25 +0000 (12:41 -0800)
committerBen Pfaff <blp@nicira.com>
Mon, 2 Mar 2009 21:42:05 +0000 (13:42 -0800)
lib/netdev.c
lib/netdev.h

index a49fe7c58216b844763f1ebcf0e8dae520582a94..de8ee62199412f2cc9302c831c50db5037d83d1a 100644 (file)
@@ -39,6 +39,7 @@
 #include <fcntl.h>
 #include <arpa/inet.h>
 #include <inttypes.h>
+#include <linux/if_link.h>
 #include <linux/if_tun.h>
 #include <linux/types.h>
 #include <linux/ethtool.h>
@@ -109,12 +110,25 @@ struct netdev {
     int changed_flags;          /* Flags that we changed. */
 };
 
+/* Policy for RTNLGRP_LINK messages.
+ *
+ * There are *many* more fields in these messages, but currently we only care
+ * about interface names. */
+static const struct nl_policy rtnlgrp_link_policy[] = {
+    [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
+    [IFLA_STATS] = { .type = NL_A_UNSPEC, .optional = true,
+                     .min_len = sizeof(struct rtnl_link_stats) },
+};
+
 /* All open network devices. */
 static struct list netdev_list = LIST_INITIALIZER(&netdev_list);
 
 /* An AF_INET socket (used for ioctl operations). */
 static int af_inet_sock = -1;
 
+/* NETLINK_ROUTE socket. */
+static struct nl_sock *rtnl_sock;
+
 /* This is set pretty low because we probably won't learn anything from the
  * additional log messages. */
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
@@ -920,6 +934,72 @@ netdev_arp_lookup(const struct netdev *netdev,
     return retval;
 }
 
+int
+netdev_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
+{
+    struct ofpbuf request;
+    struct ofpbuf *reply;
+    struct ifinfomsg *ifi;
+    const struct rtnl_link_stats *rtnl_stats;
+    struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
+    int error;
+
+    ofpbuf_init(&request, 0);
+    nl_msg_put_nlmsghdr(&request, rtnl_sock, sizeof *ifi,
+                        RTM_GETLINK, NLM_F_REQUEST);
+    ifi = ofpbuf_put_zeros(&request, sizeof *ifi);
+    ifi->ifi_family = PF_UNSPEC;
+    ifi->ifi_index = netdev->ifindex;
+    error = nl_sock_transact(rtnl_sock, &request, &reply);
+    ofpbuf_uninit(&request);
+    if (error) {
+        goto error;
+    }
+
+    if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
+                         rtnlgrp_link_policy,
+                         attrs, ARRAY_SIZE(rtnlgrp_link_policy))) {
+        ofpbuf_delete(reply);
+        error = EPROTO;
+        goto error;
+    }
+
+    if (!attrs[IFLA_STATS]) {
+        VLOG_WARN_RL(&rl, "RTM_GETLINK reply lacks stats");
+        error = EPROTO;
+        goto error;
+    }
+
+    rtnl_stats = nl_attr_get(attrs[IFLA_STATS]);
+    stats->rx_packets = rtnl_stats->rx_packets;
+    stats->tx_packets = rtnl_stats->tx_packets;
+    stats->rx_bytes = rtnl_stats->rx_bytes;
+    stats->tx_bytes = rtnl_stats->tx_bytes;
+    stats->rx_errors = rtnl_stats->rx_errors;
+    stats->tx_errors = rtnl_stats->tx_errors;
+    stats->rx_dropped = rtnl_stats->rx_dropped;
+    stats->tx_dropped = rtnl_stats->tx_dropped;
+    stats->multicast = rtnl_stats->multicast;
+    stats->collisions = rtnl_stats->collisions;
+    stats->rx_length_errors = rtnl_stats->rx_length_errors;
+    stats->rx_over_errors = rtnl_stats->rx_over_errors;
+    stats->rx_crc_errors = rtnl_stats->rx_crc_errors;
+    stats->rx_frame_errors = rtnl_stats->rx_frame_errors;
+    stats->rx_fifo_errors = rtnl_stats->rx_fifo_errors;
+    stats->rx_missed_errors = rtnl_stats->rx_missed_errors;
+    stats->tx_aborted_errors = rtnl_stats->tx_aborted_errors;
+    stats->tx_carrier_errors = rtnl_stats->tx_carrier_errors;
+    stats->tx_fifo_errors = rtnl_stats->tx_fifo_errors;
+    stats->tx_heartbeat_errors = rtnl_stats->tx_heartbeat_errors;
+    stats->tx_window_errors = rtnl_stats->tx_window_errors;
+
+    return 0;
+
+error:
+    memset(stats, 0xff, sizeof *stats);
+    return error;
+}
+
 /* Initializes 'svec' with a list of the names of all known network devices. */
 void
 netdev_enumerate(struct svec *svec)
@@ -978,14 +1058,6 @@ struct netdev_monitor {
     struct svec changed;
 };
 
-/* Policy for RTNLGRP_LINK messages.
- *
- * There are *many* more fields in these messages, but currently we only care
- * about interface names. */
-static const struct nl_policy rtnlgrp_link_policy[] = {
-    [IFLA_IFNAME] = { .type = NL_A_STRING, .optional = false },
-};
-
 static const char *lookup_netdev(const struct netdev_monitor *, const char *);
 static const char *pop_changed(struct netdev_monitor *);
 static const char *all_netdevs_changed(struct netdev_monitor *);
@@ -1146,12 +1218,21 @@ init_netdev(void)
 {
     static bool inited;
     if (!inited) {
+        int error;
+
         inited = true;
+
         fatal_signal_add_hook(restore_all_flags, NULL, true);
+
         af_inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
         if (af_inet_sock < 0) {
             ofp_fatal(errno, "socket(AF_INET)");
         }
+
+        error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
+        if (error) {
+            ofp_fatal(error, "socket(AF_NETLINK, NETLINK_ROUTE)");
+        }
     }
 }
 
index ae77397a99196c2a748ba1228afac9bd412b2b07..7dff6eff58e0163f0c31e1b87dbdc22bf59884a9 100644 (file)
@@ -68,6 +68,34 @@ enum netdev_pseudo_ethertype {
     NETDEV_ETH_TYPE_802_2        /* Receive all IEEE 802.2 frames. */
 };
 
+struct netdev_stats {
+    uint64_t rx_packets;        /* Total packets received. */
+    uint64_t tx_packets;        /* Total packets transmitted. */
+    uint64_t rx_bytes;          /* Total bytes received. */
+    uint64_t tx_bytes;          /* Total bytes transmitted. */
+    uint64_t rx_errors;         /* Bad packets received. */
+    uint64_t tx_errors;         /* Packet transmit problems. */
+    uint64_t rx_dropped;        /* No buffer space. */
+    uint64_t tx_dropped;        /* No buffer space. */
+    uint64_t multicast;         /* Multicast packets received. */
+    uint64_t collisions;
+
+    /* Detailed receive errors. */
+    uint64_t rx_length_errors;
+    uint64_t rx_over_errors;    /* Receiver ring buff overflow. */
+    uint64_t rx_crc_errors;     /* Recved pkt with crc error. */
+    uint64_t rx_frame_errors;   /* Recv'd frame alignment error. */
+    uint64_t rx_fifo_errors;    /* Recv'r fifo overrun . */
+    uint64_t rx_missed_errors;  /* Receiver missed packet. */
+
+    /* Detailed transmit errors. */
+    uint64_t tx_aborted_errors;
+    uint64_t tx_carrier_errors;
+    uint64_t tx_fifo_errors;
+    uint64_t tx_heartbeat_errors;
+    uint64_t tx_window_errors;
+};
+
 struct netdev;
 
 int netdev_open(const char *name, int ethertype, struct netdev **);
@@ -93,6 +121,7 @@ int netdev_set_flags(struct netdev *, enum netdev_flags, bool permanent);
 int netdev_turn_flags_on(struct netdev *, enum netdev_flags, bool permanent);
 int netdev_turn_flags_off(struct netdev *, enum netdev_flags, bool permanent);
 int netdev_arp_lookup(const struct netdev *, uint32_t ip, uint8_t mac[6]);
+int netdev_get_stats(const struct netdev *, struct netdev_stats *);
 
 void netdev_enumerate(struct svec *);
 int netdev_nodev_get_flags(const char *netdev_name, enum netdev_flags *);