lib/netdev-linux.c: Prevent receiving of sent packets
authorMurphy McCauley <murphy.mccauley@gmail.com>
Thu, 13 Jun 2013 21:41:21 +0000 (14:41 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 13 Jun 2013 21:43:29 +0000 (14:43 -0700)
Commit 796223f5 (netdev: Add new "struct netdev_rx" for capturing packets
from a netdev) refactored send and receive into separate netdevs.  As a
result, send and receive now use different socket descriptors (except for tap
interfaces which are treated specially).  An unintended side effect was that
all sent packets are looped back and received, which had previously been
avoided as the kernel specifically prevents this from happening on a single
socket descriptor.

To resolve the situation, a socket filter is added to the receive socket
so that it only accepts inbound packets.

Simon Horman co-discovered and initially reported this issue.

Signed-off-by: Murphy McCauley <murphy.mccauley@gmail.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Tested-by: Simon Horman <horms@verge.net.au>
Reviewed-by: Simon Horman <horms@verge.net.au>
AUTHORS
include/sparse/sys/socket.h
lib/netdev-linux.c

diff --git a/AUTHORS b/AUTHORS
index 91d4dfd..9bc4f8b 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -59,6 +59,7 @@ Lorand Jakab            lojakab@cisco.com
 Luca Giraudo            lgiraudo@nicira.com
 Martin Casado           casado@nicira.com
 Mehak Mahajan           mmahajan@nicira.com
+Murphy McCauley         murphy.mccauley@gmail.com
 Natasha Gude            natasha@nicira.com
 Neil McKee              neil.mckee@inmon.com
 Paraneetharan Chandrasekaran    paraneetharanc@gmail.com
@@ -175,7 +176,6 @@ Michael Shigorin        mike@osdn.org.ua
 Mike Bursell            mike.bursell@citrix.com
 Mike Kruze              mkruze@nicira.com
 Min Chen                ustcer.tonychan@gmail.com
-Murphy McCauley         murphy.mccauley@gmail.com
 Mikael Doverhag         mdoverhag@nicira.com
 Niklas Andersson        nandersson@nicira.com
 Padmanabhan Krishnan    kprad1@yahoo.com
index 13f61e5..64b905e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -106,7 +106,8 @@ enum {
     SO_SNDLOWAT,
     SO_SNDTIMEO,
     SO_TYPE,
-    SO_RCVBUFFORCE
+    SO_RCVBUFFORCE,
+    SO_ATTACH_FILTER
 };
 
 enum {
index d73115b..014c579 100644 (file)
@@ -22,6 +22,7 @@
 #include <fcntl.h>
 #include <arpa/inet.h>
 #include <inttypes.h>
+#include <linux/filter.h>
 #include <linux/gen_stats.h>
 #include <linux/if_ether.h>
 #include <linux/if_tun.h>
@@ -744,6 +745,14 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
     } else {
         struct sockaddr_ll sll;
         int ifindex;
+        /* Result of tcpdump -dd inbound */
+        static struct sock_filter filt[] = {
+            { 0x28, 0, 0, 0xfffff004 }, /* ldh [0] */
+            { 0x15, 0, 1, 0x00000004 }, /* jeq #4     jt 2  jf 3 */
+            { 0x6, 0, 0, 0x00000000 },  /* ret #0 */
+            { 0x6, 0, 0, 0x0000ffff }   /* ret #65535 */
+        };
+        static struct sock_fprog fprog = { ARRAY_SIZE(filt), filt };
 
         /* Create file descriptor. */
         fd = socket(PF_PACKET, SOCK_RAW, 0);
@@ -776,6 +785,16 @@ netdev_linux_rx_open(struct netdev *netdev_, struct netdev_rx **rxp)
                      netdev_get_name(netdev_), strerror(error));
             goto error;
         }
+
+        /* Filter for only inbound packets. */
+        error = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog,
+                           sizeof fprog);
+        if (error) {
+            error = errno;
+            VLOG_ERR("%s: failed attach filter (%s)",
+                     netdev_get_name(netdev_), strerror(error));
+            goto error;
+        }
     }
 
     rx = xmalloc(sizeof *rx);
@@ -910,7 +929,8 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
             /* Use the tap 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. */
+             * tap device.  This doesn't occur on other interface types
+             * because we attach a socket filter to the rx socket. */
             struct netdev_linux *netdev = netdev_linux_cast(netdev_);
 
             retval = write(netdev->state.tap.fd, data, size);