dpif: New function dpif_normalize_type().
[sliver-openvswitch.git] / lib / netdev-linux.c
index 6b0d014..6b1124f 100644 (file)
@@ -368,8 +368,9 @@ struct netdev_linux {
     int fd;
 };
 
-/* An AF_INET socket (used for ioctl operations). */
-static int af_inet_sock = -1;
+/* 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;
@@ -443,6 +444,15 @@ 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. */
@@ -820,15 +830,48 @@ static int
 netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    for (;;) {
+        ssize_t retval;
 
-    /* XXX should support sending even if 'ethertype' was NETDEV_ETH_TYPE_NONE.
-     */
-    if (netdev->fd < 0) {
-        return EPIPE;
-    }
+        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;
+
+            error = get_ifindex(netdev_, &ifindex);
+            if (error) {
+                return error;
+            }
+
+            /* 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(af_packet_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 = write(netdev->fd, data, size);
         if (retval < 0) {
             /* The Linux AF_PACKET implementation never blocks waiting for room
              * for packets, instead returning ENOBUFS.  Translate this into
@@ -1115,9 +1158,9 @@ netdev_linux_update_is_pseudo(struct netdev_dev_linux *netdev_dev)
 static void
 swap_uint64(uint64_t *a, uint64_t *b)
 {
-    *a ^= *b;
-    *b ^= *a;
-    *a ^= *b;
+    uint64_t tmp = *a;
+    *a = *b;
+    *b = tmp;
 }
 
 /* Retrieves current device stats for 'netdev'. */
@@ -1971,7 +2014,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;
 
@@ -2038,7 +2081,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;