Merge 'next' into 'master'.
[sliver-openvswitch.git] / lib / netdev-linux.c
index c41b19d..a401c60 100644 (file)
@@ -373,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;
@@ -411,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)
@@ -447,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. */
@@ -682,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;
@@ -843,6 +835,12 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
             struct iovec iov;
             int ifindex;
             int error;
+            int sock;
+
+            sock = af_packet_sock();
+            if (sock < 0) {
+                return sock;
+            }
 
             error = get_ifindex(netdev_, &ifindex);
             if (error) {
@@ -866,7 +864,7 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
             msg.msg_controllen = 0;
             msg.msg_flags = 0;
 
-            retval = sendmsg(af_packet_sock, &msg, 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
@@ -4240,3 +4238,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;
+}