Browse Source

[2893] Use BPF packet filter for BSDs.

Marcin Siodelski 10 years ago
parent
commit
3f3d1c27f5
3 changed files with 23 additions and 30 deletions
  1. 1 1
      src/bin/dhcp4/tests/dhcp4_test_utils.h
  2. 20 25
      src/lib/dhcp/iface_mgr.cc
  3. 2 4
      src/lib/dhcp/iface_mgr_bsd.cc

+ 1 - 1
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -64,7 +64,7 @@ public:
     }
 
     /// Does nothing.
-    virtual SocketInfo openSocket(const Iface&,
+    virtual SocketInfo openSocket(Iface&,
                                   const isc::asiolink::IOAddress& addr,
                                   const uint16_t port, const bool, const bool) {
         return (SocketInfo(addr, port, 0));

+ 20 - 25
src/lib/dhcp/iface_mgr.cc

@@ -428,18 +428,6 @@ bool
 IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
                        IfaceMgrErrorMsgCallback error_handler) {
     int count = 0;
-
-// This option is used to bind sockets to particular interfaces.
-// This is currently the only way to discover on which interface
-// the broadcast packet has been received. If this option is
-// not supported then only one interface should be confugured
-// to listen for broadcast traffic.
-#ifdef SO_BINDTODEVICE
-    const bool bind_to_device = true;
-#else
-    const bool bind_to_device = false;
-#endif
-
     int bcast_num = 0;
 
     for (IfaceCollection::iterator iface = ifaces_.begin();
@@ -467,17 +455,26 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
             // options on the socket so as it can receive and send broadcast
             // messages.
             if (iface->flag_broadcast_ && use_bcast) {
-                // If our OS supports binding socket to a device we can listen
-                // for broadcast messages on multiple interfaces. Otherwise we
-                // bind to INADDR_ANY address but we can do it only once. Thus,
-                // if one socket has been bound we can't do it any further.
-                if (!bind_to_device && bcast_num > 0) {
+                // The DHCP server must have means to determine which interface
+                // the broadcast packets are coming from. This is achieved by
+                // binding a socket to the device (interface) and specialized
+                // packet filters (e.g. BPF and LPF) implement this mechanism.
+                // If the PktFilterInet (generic one) is used, the socket is
+                // bound to INADDR_ANY which effectively binds the socket to
+                // all addresses on all interfaces. So, only one of those can
+                // be opened. Currently, the direct response support is
+                // provided by the PktFilterLPF and PktFilterBPF, so by checking
+                // the support for direct response we actually determine that
+                // one of those objects is in use. For all other objects we
+                // assume that binding to the device is not supported and we
+                // cease opening sockets and display the appropriate message.
+                if (!isDirectResponseSupported() && bcast_num > 0) {
                     IFACEMGR_ERROR(SocketConfigError, error_handler,
-                                   "SO_BINDTODEVICE socket option is"
-                                   " not supported on this OS;"
-                                   " therefore, DHCP server can only"
-                                   " listen broadcast traffic on a"
-                                   " single interface");
+                                   "Binding socket to an interface is not"
+                                   " supported on this OS; therefore only"
+                                   " one socket listening to broadcast traffic"
+                                   " can be opened. Sockets will not be opened"
+                                   " on remaining interfaces");
                     continue;
 
                 } else {
@@ -496,9 +493,7 @@ IfaceMgr::openSockets4(const uint16_t port, const bool use_bcast,
                     // Binding socket to an interface is not supported so we
                     // can't open any more broadcast sockets. Increase the
                     // number of open broadcast sockets.
-                    if (!bind_to_device) {
-                        ++bcast_num;
-                    }
+                    ++bcast_num;
                 }
 
             } else {

+ 2 - 4
src/lib/dhcp/iface_mgr_bsd.cc

@@ -18,7 +18,7 @@
 
 #include <dhcp/iface_mgr.h>
 #include <dhcp/iface_mgr_error_handler.h>
-#include <dhcp/pkt_filter_inet.h>
+#include <dhcp/pkt_filter_bpf.h>
 #include <exceptions/exceptions.h>
 
 #include <sys/types.h>
@@ -145,9 +145,7 @@ bool IfaceMgr::os_receive4(struct msghdr& /*m*/, Pkt4Ptr& /*pkt*/) {
 
 void
 IfaceMgr::setMatchingPacketFilter(const bool /* direct_response_desired */) {
-    // @todo Currently we ignore the preference to use direct traffic
-    // because it hasn't been implemented for BSD systems.
-    setPacketFilter(PktFilterPtr(new PktFilterInet()));
+    setPacketFilter(PktFilterPtr(new PktFilterBPF()));
 }
 
 bool