From 6b9d3b3843c5c76d429c120193d040088d75ec7f Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 2 Mar 2009 12:41:25 -0800 Subject: [PATCH] netdev: New function netdev_get_stats(). --- lib/netdev.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++----- lib/netdev.h | 29 ++++++++++++++++ 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index a49fe7c5..de8ee621 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -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)"); + } } } diff --git a/lib/netdev.h b/lib/netdev.h index ae77397a..7dff6eff 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -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 *); -- 2.30.2