#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>
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);
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)
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 *);
{
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)");
+ }
}
}
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 **);
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 *);