Make the source tree sparse clean.
[sliver-openvswitch.git] / lib / netdev-linux.c
index 50bec08..fde686c 100644 (file)
@@ -15,6 +15,9 @@
  */
 
 #include <config.h>
+
+#include "netdev-linux.h"
+
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -370,7 +373,6 @@ struct netdev_linux {
 
 /* Sockets used for ioctl operations. */
 static int af_inet_sock = -1;   /* AF_INET, SOCK_DGRAM. */
-static int af_packet_sock = -1; /* AF_PACKET, SOCK_RAW. */
 
 /* A Netlink routing socket that is not subscribed to any multicast groups. */
 static struct nl_sock *rtnl_sock;
@@ -408,6 +410,7 @@ static int set_etheraddr(const char *netdev_name, int hwaddr_family,
                          const uint8_t[ETH_ADDR_LEN]);
 static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats);
 static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats);
+static int af_packet_sock(void);
 
 static bool
 is_netdev_linux_class(const struct netdev_class *netdev_class)
@@ -444,15 +447,6 @@ netdev_linux_init(void)
         status = af_inet_sock >= 0 ? 0 : errno;
         if (status) {
             VLOG_ERR("failed to create inet socket: %s", strerror(status));
-        } else {
-            /* Create AF_PACKET socket. */
-            af_packet_sock = socket(AF_PACKET, SOCK_RAW, 0);
-            status = af_packet_sock >= 0 ? 0 : errno;
-            if (status) {
-                VLOG_ERR("failed to create packet socket: %s",
-                         strerror(status));
-            }
-            set_nonblocking(af_packet_sock);
         }
 
         /* Create rtnetlink socket. */
@@ -679,7 +673,8 @@ netdev_linux_open(struct netdev_dev *netdev_dev_, int ethertype,
         protocol = (ethertype == NETDEV_ETH_TYPE_ANY ? ETH_P_ALL
                     : ethertype == NETDEV_ETH_TYPE_802_2 ? ETH_P_802_2
                     : ethertype);
-        netdev->fd = socket(PF_PACKET, SOCK_RAW, htons(protocol));
+        netdev->fd = socket(PF_PACKET, SOCK_RAW,
+                            (OVS_FORCE int) htons(protocol));
         if (netdev->fd < 0) {
             error = errno;
             goto error;
@@ -829,36 +824,55 @@ netdev_linux_drain(struct netdev *netdev_)
 static int
 netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
 {
-    struct sockaddr_ll sll;
-    struct msghdr msg;
-    struct iovec iov;
-    int ifindex;
-    int error;
+    struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    for (;;) {
+        ssize_t retval;
 
-    error = get_ifindex(netdev_, &ifindex);
-    if (error) {
-        return error;
-    }
+        if (netdev->fd < 0) {
+            /* Use our AF_PACKET socket to send to this device. */
+            struct sockaddr_ll sll;
+            struct msghdr msg;
+            struct iovec iov;
+            int ifindex;
+            int error;
+            int sock;
 
-    /* We don't bother setting most fields in sockaddr_ll because the kernel
-     * ignores them for SOCK_RAW. */
-    memset(&sll, 0, sizeof sll);
-    sll.sll_family = AF_PACKET;
-    sll.sll_ifindex = ifindex;
+            sock = af_packet_sock();
+            if (sock < 0) {
+                return sock;
+            }
 
-    iov.iov_base = (void *) data;
-    iov.iov_len = size;
+            error = get_ifindex(netdev_, &ifindex);
+            if (error) {
+                return error;
+            }
 
-    msg.msg_name = &sll;
-    msg.msg_namelen = sizeof sll;
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-    msg.msg_control = NULL;
-    msg.msg_controllen = 0;
-    msg.msg_flags = 0;
+            /* We don't bother setting most fields in sockaddr_ll because the
+             * kernel ignores them for SOCK_RAW. */
+            memset(&sll, 0, sizeof sll);
+            sll.sll_family = AF_PACKET;
+            sll.sll_ifindex = ifindex;
+
+            iov.iov_base = (void *) data;
+            iov.iov_len = size;
+
+            msg.msg_name = &sll;
+            msg.msg_namelen = sizeof sll;
+            msg.msg_iov = &iov;
+            msg.msg_iovlen = 1;
+            msg.msg_control = NULL;
+            msg.msg_controllen = 0;
+            msg.msg_flags = 0;
+
+            retval = sendmsg(sock, &msg, 0);
+        } else {
+            /* Use the netdev's own fd to send to this device.  This is
+             * essential for tap devices, because packets sent to a tap device
+             * with an AF_PACKET socket will loop back to be *received* again
+             * on the tap device. */
+            retval = write(netdev->fd, data, size);
+        }
 
-    for (;;) {
-        ssize_t retval = sendmsg(af_packet_sock, &msg, 0);
         if (retval < 0) {
             /* The Linux AF_PACKET implementation never blocks waiting for room
              * for packets, instead returning ENOBUFS.  Translate this into
@@ -2001,7 +2015,7 @@ netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop,
     while (fgets(line, sizeof line, stream)) {
         if (++ln >= 2) {
             char iface[17];
-            uint32_t dest, gateway, mask;
+            ovs_be32 dest, gateway, mask;
             int refcnt, metric, mtu;
             unsigned int flags, use, window, irtt;
 
@@ -2068,7 +2082,7 @@ netdev_linux_get_status(const struct netdev *netdev, struct shash *sh)
  * ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */
 static int
 netdev_linux_arp_lookup(const struct netdev *netdev,
-                        uint32_t ip, uint8_t mac[ETH_ADDR_LEN])
+                        ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
 {
     struct arpreq r;
     struct sockaddr_in sin;
@@ -3912,7 +3926,55 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes)
     unsigned int min_burst = tc_buffer_per_jiffy(Bps) + mtu;
     return tc_bytes_to_ticks(Bps, MAX(burst_bytes, min_burst));
 }
-
+\f
+/* Public utility functions. */
+
+#define COPY_NETDEV_STATS                                   \
+    dst->rx_packets = src->rx_packets;                      \
+    dst->tx_packets = src->tx_packets;                      \
+    dst->rx_bytes = src->rx_bytes;                          \
+    dst->tx_bytes = src->tx_bytes;                          \
+    dst->rx_errors = src->rx_errors;                        \
+    dst->tx_errors = src->tx_errors;                        \
+    dst->rx_dropped = src->rx_dropped;                      \
+    dst->tx_dropped = src->tx_dropped;                      \
+    dst->multicast = src->multicast;                        \
+    dst->collisions = src->collisions;                      \
+    dst->rx_length_errors = src->rx_length_errors;          \
+    dst->rx_over_errors = src->rx_over_errors;              \
+    dst->rx_crc_errors = src->rx_crc_errors;                \
+    dst->rx_frame_errors = src->rx_frame_errors;            \
+    dst->rx_fifo_errors = src->rx_fifo_errors;              \
+    dst->rx_missed_errors = src->rx_missed_errors;          \
+    dst->tx_aborted_errors = src->tx_aborted_errors;        \
+    dst->tx_carrier_errors = src->tx_carrier_errors;        \
+    dst->tx_fifo_errors = src->tx_fifo_errors;              \
+    dst->tx_heartbeat_errors = src->tx_heartbeat_errors;    \
+    dst->tx_window_errors = src->tx_window_errors
+
+/* Copies 'src' into 'dst', performing format conversion in the process. */
+void
+netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst,
+                                  const struct rtnl_link_stats *src)
+{
+    COPY_NETDEV_STATS;
+}
+
+/* Copies 'src' into 'dst', performing format conversion in the process. */
+void
+netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst,
+                                    const struct rtnl_link_stats64 *src)
+{
+    COPY_NETDEV_STATS;
+}
+
+/* Copies 'src' into 'dst', performing format conversion in the process. */
+void
+netdev_stats_to_rtnl_link_stats64(struct rtnl_link_stats64 *dst,
+                                  const struct netdev_stats *src)
+{
+    COPY_NETDEV_STATS;
+}
 \f
 /* Utility functions. */
 
@@ -3932,7 +3994,6 @@ get_stats_via_netlink(int ifindex, 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;
 
@@ -3960,28 +4021,7 @@ get_stats_via_netlink(int ifindex, struct netdev_stats *stats)
         return EPROTO;
     }
 
-    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;
+    netdev_stats_from_rtnl_link_stats(stats, nl_attr_get(attrs[IFLA_STATS]));
 
     ofpbuf_delete(reply);
 
@@ -4196,3 +4236,22 @@ netdev_linux_get_ipv4(const struct netdev *netdev, struct in_addr *ip,
     }
     return error;
 }
+
+/* Returns an AF_PACKET raw socket or a negative errno value. */
+static int
+af_packet_sock(void)
+{
+    static int sock = INT_MIN;
+
+    if (sock == INT_MIN) {
+        sock = socket(AF_PACKET, SOCK_RAW, 0);
+        if (sock >= 0) {
+            set_nonblocking(sock);
+        } else {
+            sock = -errno;
+            VLOG_ERR("failed to create packet socket: %s", strerror(errno));
+        }
+    }
+
+    return sock;
+}