mirror of
https://github.com/zeromq/libzmq.git
synced 2025-11-02 05:46:24 +01:00
Add socket option BINDTODEVICE
Linux now supports Virtual Routing and Forwarding (VRF) as per: https://www.kernel.org/doc/Documentation/networking/vrf.txt In order for an application to bind or connect to a socket with an address in a VRF, they need to first bind the socket to the VRF device: setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, strlen(dev)+1); Note "dev" is the VRF device, eg. VRF "blue", rather than an interface enslaved to the VRF. Add a new socket option, ZMQ_BINDTODEVICE, to bind a socket to a device. In general, if a socket is bound to a device, eg. an interface, only packets received from that particular device are processed by the socket. If device is a VRF device, then subsequent binds/connects to that socket use addresses in the VRF routing table.
This commit is contained in:
13
src/ip.cpp
13
src/ip.cpp
@@ -217,3 +217,16 @@ int zmq::set_nosigpipe (fd_t s_)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zmq::bind_to_device (fd_t s_, std::string &bound_device_)
|
||||
{
|
||||
#ifdef ZMQ_HAVE_SO_BINDTODEVICE
|
||||
int rc = setsockopt(s_, SOL_SOCKET, SO_BINDTODEVICE, bound_device_.c_str (), bound_device_.length ());
|
||||
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
wsa_assert (rc != SOCKET_ERROR);
|
||||
#else
|
||||
errno_assert (rc == 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -56,6 +56,9 @@ namespace zmq
|
||||
// Return 0 on success, -1 if the connection has been closed by the peer
|
||||
int set_nosigpipe (fd_t s_);
|
||||
|
||||
// Binds the underlying socket to the given device, eg. VRF or interface
|
||||
void bind_to_device (fd_t s_, std::string &bound_device_);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,16 @@
|
||||
#include "err.hpp"
|
||||
#include "macros.hpp"
|
||||
|
||||
#ifndef ZMQ_HAVE_WINDOWS
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#if defined IFNAMSIZ
|
||||
#define BINDDEVSIZ IFNAMSIZ
|
||||
#else
|
||||
#define BINDDEVSIZ 16
|
||||
#endif
|
||||
|
||||
zmq::options_t::options_t () :
|
||||
sndhwm (1000),
|
||||
rcvhwm (1000),
|
||||
@@ -605,6 +615,19 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_BINDTODEVICE:
|
||||
if (optval_ == NULL && optvallen_ == 0) {
|
||||
bound_device.clear ();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (optval_ != NULL && optvallen_ > 0 && optvallen_ <= BINDDEVSIZ) {
|
||||
bound_device =
|
||||
std::string ((const char *) optval_, optvallen_);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#if defined (ZMQ_ACT_MILITANT)
|
||||
// There are valid scenarios for probing with unknown socket option
|
||||
@@ -1021,6 +1044,14 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_BINDTODEVICE:
|
||||
if (*optvallen_ >= bound_device.size () + 1) {
|
||||
memcpy (optval_, bound_device.c_str (), bound_device.size () + 1);
|
||||
*optvallen_ = bound_device.size () + 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
#if defined (ZMQ_ACT_MILITANT)
|
||||
malformed = false;
|
||||
|
||||
@@ -240,6 +240,9 @@ namespace zmq
|
||||
// will be used as the File Descriptor instead of allocating a new
|
||||
// one via the socket () system call.
|
||||
int use_fd;
|
||||
|
||||
// Device to bind the underlying socket to, eg. VRF or interface
|
||||
std::string bound_device;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -334,6 +334,10 @@ int zmq::socks_connecter_t::connect_to_proxy ()
|
||||
if (options.tos != 0)
|
||||
set_ip_type_of_service (s, options.tos);
|
||||
|
||||
// Bind the socket to a device if applicable
|
||||
if (!options.bound_device.empty ())
|
||||
bind_to_device (s, options.bound_device);
|
||||
|
||||
// Set the socket to non-blocking mode so that we get async connect().
|
||||
unblock_socket (s);
|
||||
|
||||
|
||||
@@ -305,6 +305,10 @@ int zmq::tcp_connecter_t::open ()
|
||||
if (options.tos != 0)
|
||||
set_ip_type_of_service (s, options.tos);
|
||||
|
||||
// Bind the socket to a device if applicable
|
||||
if (!options.bound_device.empty ())
|
||||
bind_to_device (s, options.bound_device);
|
||||
|
||||
// Set the socket to non-blocking mode so that we get async connect().
|
||||
unblock_socket (s);
|
||||
|
||||
|
||||
@@ -212,6 +212,10 @@ int zmq::tcp_listener_t::set_address (const char *addr_)
|
||||
if (options.tos != 0)
|
||||
set_ip_type_of_service (s, options.tos);
|
||||
|
||||
// Bind the socket to a device if applicable
|
||||
if (!options.bound_device.empty ())
|
||||
bind_to_device (s, options.bound_device);
|
||||
|
||||
// Set the socket buffer limits for the underlying socket.
|
||||
if (options.sndbuf >= 0)
|
||||
set_tcp_send_buffer (s, options.sndbuf);
|
||||
|
||||
@@ -123,6 +123,10 @@ void zmq::udp_engine_t::plug (io_thread_t* io_thread_, session_base_t *session_)
|
||||
errno_assert (rc == 0);
|
||||
#endif
|
||||
|
||||
// Bind the socket to a device if applicable
|
||||
if (!options.bound_device.empty ())
|
||||
bind_to_device (fd, options.bound_device);
|
||||
|
||||
rc = bind (fd, address->resolved.udp_addr->bind_addr (),
|
||||
address->resolved.udp_addr->bind_addrlen ());
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
|
||||
Reference in New Issue
Block a user