This sets SO_MARK on the socket.
New option could be used for routing multiple pingcheck instances
to different gateways running over the same network interface.
config/option/nameserveroption.cpp
config/option/pingfaillimitoption.cpp
config/option/sourcenetworkinterfaceoption.cpp
+ config/option/netmarkoption.cpp
config/option/statusnotifiercmdoption.cpp
config/option/versionoption.cpp
config/option/ratiorandomhostsoption.cpp
LogFileName( "" ),
ConfigFileName( "" ),
SourceNetworkInterface( "" ),
+ NetMark(0),
NameServer( "" ),
HostsDownLimit( 0 ),
MinHostsDownLimit( 0 ),
SourceNetworkInterface = source_network_interface;
}
+NetmarkType Configuration::get_netmark() const
+{
+ return NetMark;
+}
+
+void Configuration::set_netmark(
+ const NetmarkType net_mark
+)
+{
+ NetMark = net_mark;
+}
+
int Configuration::get_hosts_down_limit() const
{
return HostsDownLimit;
#include "config/host.h"
#include "host/loglevel.h"
#include "host/logoutput.h"
+#include "host/networkinterface.hpp"
//-----------------------------------------------------------------------------
// Configuration
const std::string &source_network_interface
);
+ NetmarkType get_netmark() const;
+ void set_netmark(const NetmarkType net_mark);
+
int get_hosts_down_limit() const;
void set_hosts_down_limit( const int hosts_down_limit );
std::string LogFileName;
std::string ConfigFileName;
std::string SourceNetworkInterface;
+ NetmarkType NetMark;
std::string NameServer;
int HostsDownLimit;
int MinHostsDownLimit;
#include "config/option/logoutputoption.h"
#include "config/option/logfileoption.h"
#include "config/option/nameserveroption.h"
+#include "config/option/netmarkoption.h"
#include "config/option/pingfaillimitoption.h"
#include "config/option/sourcenetworkinterfaceoption.h"
#include "config/option/statusnotifiercmdoption.h"
ConfigurationOptionItem nameserver( new NameserverOption );
ConfigOptions.push_back( nameserver );
+ ConfigurationOptionItem netmark( new NetmarkOption );
+ ConfigOptions.push_back( netmark );
+
ConfigurationOptionItem ping_fail_limit( new PingFailLimitOption );
ConfigOptions.push_back( ping_fail_limit );
--- /dev/null
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+ */
+
+#include "config/option/netmarkoption.h"
+#include "host/networkinterface.hpp"
+
+#include <logfunc.hpp>
+
+using namespace std;
+using boost::program_options::value;
+using boost::program_options::variables_map;
+using I2n::Logger::GlobalLogger;
+
+//-----------------------------------------------------------------------------
+// NetmarkOption
+//-----------------------------------------------------------------------------
+
+NetmarkOption::NetmarkOption() :
+ ConfigurationOption(
+ "net-mark",
+ value<NetmarkType>()->default_value( 0 ),
+ "Mark outgoing network packets (for policy based routing)"
+ )
+{
+}
+
+NetmarkOption::~NetmarkOption()
+{
+}
+
+bool NetmarkOption::parse(
+ const variables_map& vm,
+ Configuration *configuration
+)
+{
+ if ( 1 <= vm.count( get_command_string() ) )
+ {
+ NetmarkType net_mark = vm[ get_command_string() ].as<NetmarkType> ();
+ configuration->set_netmark( net_mark );
+
+ GlobalLogger.info() << get_command_string() << "="
+ << net_mark << endl;
+
+ return true;
+ }
+
+ return false;
+}
--- /dev/null
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+ */
+
+#ifndef NETMARK_OPTION_H
+#define NETMARK_OPTION_H
+
+#include <boost/program_options.hpp>
+
+#include "config/option/configurationoption.h"
+
+//-----------------------------------------------------------------------------
+// NetmarkOption
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief This class represents the "net-mark"
+ * configuration option.
+ */
+class NetmarkOption : public ConfigurationOption
+{
+public:
+ NetmarkOption();
+ virtual ~NetmarkOption();
+
+ virtual bool parse(
+ const boost::program_options::variables_map &vm,
+ Configuration *configuration
+ );
+
+};
+
+#endif // NETMARK_OPTION_H
typedef const struct sockaddr* const_sockaddr_ptr_t;
typedef const struct sockaddr_in* const_sockaddr_in_ptr_t;
typedef const struct sockaddr_in6* const_sockaddr_in6_ptr_t;
+typedef uint32_t NetmarkType;
//-----------------------------------------------------------------------------
// NetworkInterface
NetworkInterface(
const std::string &nic_name,
- SocketType &boost_socket
+ SocketType &boost_socket,
+ const NetmarkType net_mark
);
bool bind();
+ bool set_mark();
std::string get_name() const;
const std::string Name;
/// The socket used in this network interface
SocketType &Socket;
-
+ /// Mark used for outgoing packets (f.e. routing decisions)
+ NetmarkType Netmark;
};
template<typename SocketType, typename Protocol>
NetworkInterface<SocketType, Protocol>::NetworkInterface(
const std::string &nic_name,
- SocketType &boost_socket
+ SocketType &boost_socket,
+ NetmarkType net_mark
) :
Name( nic_name ),
- Socket( boost_socket )
+ Socket( boost_socket ),
+ Netmark( net_mark )
{
BOOST_ASSERT( !nic_name.empty() );
}
}
/**
+ * @brief Set net mark for outgoing packets.
+ *
+ * @return true if SO_MARK was successfully, false otherwise.
+ */
+template<typename SocketType, typename Protocol>
+bool NetworkInterface<SocketType, Protocol>::set_mark()
+{
+ // don't bother the kernel if not configured
+ if (Netmark == 0)
+ return true;
+
+ int ret = ::setsockopt(
+ Socket.native(),
+ SOL_SOCKET,
+ SO_MARK,
+ static_cast<const void *>(&Netmark),
+ sizeof(NetmarkType)
+ );
+ if ( ret == -1 )
+ {
+ I2n::Logger::GlobalLogger.error()
+ << "Could not set SO_MARK for interface " << Name << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+/**
* @brief Get the network interface name.
*
* @return A string representing the name of the network interface.
const PingProtocol protocol,
const IoServiceItem io_serv,
const string &network_interface,
+ const NetmarkType net_mark,
const int ping_reply_timeout
)
{
{
PingerItem new_pinger = IcmpPinger::create( io_serv, icmp::v4(),
network_interface,
+ net_mark,
ping_reply_timeout );
return new_pinger;
}
{
PingerItem new_pinger = IcmpPinger::create( io_serv, icmp::v6(),
network_interface,
+ net_mark,
ping_reply_timeout );
return new_pinger;
}
{
PingerItem new_pinger = TcpPinger::create( io_serv, tcp_raw_protocol::v4(),
network_interface,
+ net_mark,
ping_reply_timeout );
return new_pinger;
}
{
PingerItem new_pinger = TcpPinger::create( io_serv, tcp_raw_protocol::v6(),
network_interface,
+ net_mark,
ping_reply_timeout );
return new_pinger;
}
#include "host/pinger.h"
#include "host/pingprotocol.h"
+#include "host/networkinterface.hpp"
//-----------------------------------------------------------------------------
// PingerFactory
const PingProtocol protocol,
const IoServiceItem io_serv,
const std::string &network_interface,
+ const NetmarkType net_mark,
const int ping_reply_timeout
);
PingScheduler::PingScheduler(
const IoServiceItem io_serv,
const string &network_interface,
+ const NetmarkType net_mark,
const string &destination_address,
const uint16_t destination_port,
const PingProtocolList &ping_protocol_list,
) :
IoService( io_serv ),
NetworkInterfaceName( network_interface ),
+ Netmark( net_mark ),
DestinationAddress( destination_address ),
DestinationPort( destination_port ),
Protocols( ping_protocol_list ),
Pingers.push_back(
PingerFactory::createPinger(*ProtocolIter, IoService,
NetworkInterfaceName,
+ Netmark,
PingReplyTimeout) );
// remember when pinging started
#include <boost/shared_ptr.hpp>
#include "link/linkstatus.h"
+#include "host/networkinterface.hpp"
#include "host/hoststatus.h"
#include "host/pingstatus.h"
#include "host/pinger.h"
PingScheduler(
const IoServiceItem io_service,
const std::string &network_interface,
+ const NetmarkType net_mark,
const std::string &destination_address,
const uint16_t destination_port,
const PingProtocolList &ping_protocol_list,
IoServiceItem IoService;
/// The network interface name
std::string NetworkInterfaceName;
+ /// Mark used for the network packets (if non-zero)
+ NetmarkType Netmark;
/// The address to ping
std::string DestinationAddress;
/// The port to ping at destination host (same for all protocols)
const IoServiceItem io_serv,
const icmp::socket::protocol_type &protocol,
const string &source_network_interface,
+ const NetmarkType net_mark,
const int echo_reply_timeout_in_sec )
{
// get distributor
IcmpPacketDistributorItem distributor = IcmpPacketDistributor::get_distributor(
- protocol, source_network_interface, io_serv);
+ protocol, source_network_interface, net_mark, io_serv);
// create pinger
IcmpPinger *ptr = new IcmpPinger(io_serv, protocol, echo_reply_timeout_in_sec, distributor);
IcmpPacketDistributorItem IcmpPacketDistributor::get_distributor(
const icmp::socket::protocol_type &protocol,
const std::string &network_interface,
+ const NetmarkType net_mark,
const IoServiceItem io_serv )
{
IcmpPacketDistributor::DistributorInstanceIdentifier identifier(
else
protocol_str = "unknown protocol!";
+ // note about marks: All interfaces use the same (global) mark setting.
+ // connd creates one pingcheck per connection anyway.
+ std::string mark_str;
+ if (net_mark != 0)
+ {
+ ostringstream out;
+ out << " (mark: " << net_mark << ")";
+ mark_str = out.str();
+ }
+
GlobalLogger.info() << "Creating IcmpPacketDistributor for interface "
<< network_interface << " and protocol "
- << protocol_str << std::endl;
+ << protocol_str
+ << mark_str
+ << std::endl;
+
IcmpPacketDistributorItem new_instance( new IcmpPacketDistributor(
- protocol, network_interface, io_serv ) );
+ protocol, network_interface, net_mark, io_serv ) );
Instances[identifier] = new_instance;
}
IcmpPacketDistributor::IcmpPacketDistributor(
const icmp::socket::protocol_type &protocol,
const std::string &network_interface,
+ const NetmarkType net_mark,
const IoServiceItem io_serv ):
Protocol( protocol ),
Socket( new icmp::socket(*io_serv, protocol) ),
//Socket->set_option(option);
NetworkInterface<icmp::socket, boost::asio::ip::icmp>
- NetInterface( network_interface, *Socket );
+ NetInterface( network_interface, *Socket, net_mark );
if ( !NetInterface.bind() )
{
<< ::strerror( errno ) << std::endl;
}
+ if ( !NetInterface.set_mark() )
+ {
+ GlobalLogger.error()
+ << "Trouble creating IcmpPacketDistributor for interface "
+ << network_interface// << " and protocol " << protocol
+ << ": could not set the mark on the interface: "
+ << ::strerror( errno ) << std::endl;
+ }
+
register_receive_handler();
}
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
+#include "host/networkinterface.hpp"
#include "host/pinger.h"
#include "host/pingstatus.h"
#include "icmp/icmppacket.h"
static IcmpPacketDistributorItem get_distributor(
const icmp::socket::protocol_type &protocol,
const std::string &network_interface,
+ const NetmarkType net_mark,
const IoServiceItem io_serv
);
IcmpPacketDistributor(
const icmp::socket::protocol_type &protocol,
const std::string &network_interface,
+ const NetmarkType net_mark,
const IoServiceItem io_serv
);
IcmpPacketDistributor(IcmpPacketDistributor const&);
const IoServiceItem io_serv,
const boost::asio::ip::icmp::socket::protocol_type &protocol,
const std::string &source_network_interface,
+ const NetmarkType net_mark,
const int echo_reply_timeout_in_sec
);
int congest_caused_by_fail_limit_percentage = 99;
int ping_timeout_factor = 5;
+ const NetmarkType net_mark = configuration->get_netmark();
+
BOOST_FOREACH( const HostItem &host, hosts )
{
string destination_address = host->get_address();
new PingScheduler(
io_service,
network_interface,
+ net_mark,
destination_address,
destination_port,
protocol_list,
const IoServiceItem io_serv,
const tcp_raw_protocol::socket::protocol_type &protocol,
const string &source_network_interface_name,
+ const NetmarkType net_mark,
const int rst_reply_timeout_in_sec
) :
DestinationEndpoint(),
Protocol( protocol ),
Socket( *io_serv, Protocol ),
- NetInterface( source_network_interface_name, Socket ),
+ NetInterface( source_network_interface_name, Socket, net_mark ),
TcpSegmentReceiveTimer( *io_serv ),
Identifier( 0 ),
SequenceNumber( 0 ),
const IoServiceItem io_serv,
const tcp_raw_protocol::socket::protocol_type &protocol,
const string &source_network_interface_name,
+ const NetmarkType net_mark,
const int rst_reply_timeout_in_sec )
{
TcpPinger *ptr = new TcpPinger(io_serv, protocol, source_network_interface_name,
+ net_mark,
rst_reply_timeout_in_sec);
PingerItem shared_ptr(ptr);
Pinger::WeakPtr weak_ptr( shared_ptr );
const IoServiceItem io_serv,
const boost::asio::ip::tcp_raw_protocol::socket::protocol_type &protocol,
const std::string &source_network_interface_name,
+ const NetmarkType net_mark,
const int rst_reply_timeout_in_sec
);
const IoServiceItem io_serv,
const boost::asio::ip::tcp_raw_protocol::socket::protocol_type &protocol,
const std::string &source_network_interface_name,
+ const NetmarkType net_mark,
const int rst_reply_timeout_in_sec
);
${CMAKE_SOURCE_DIR}/src/config/option/logoutputoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/logfileoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/nameserveroption.cpp
+ ${CMAKE_SOURCE_DIR}/src/config/option/netmarkoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/pingfaillimitoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/sourcenetworkinterfaceoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/statusnotifiercmdoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/logoutputoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/logfileoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/nameserveroption.cpp
+ ${CMAKE_SOURCE_DIR}/src/config/option/netmarkoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/pingfaillimitoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/sourcenetworkinterfaceoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/statusnotifiercmdoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/logoutputoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/logfileoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/nameserveroption.cpp
+ ${CMAKE_SOURCE_DIR}/src/config/option/netmarkoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/pingfaillimitoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/sourcenetworkinterfaceoption.cpp
${CMAKE_SOURCE_DIR}/src/config/option/statusnotifiercmdoption.cpp
BOOST_AUTO_TEST_CASE( normal_options )
{
- const int argc = 25;
+ const int argc = 26;
const char *argv[argc] = {
"./pingcheck",
"--daemon",
"--config-file=conf/config_file.conf",
"--default-source-network-interface=eth0",
+ "--net-mark=42424242",
"--nameserver=localhost",
"--hosts-down-limit=2",
"--ping-fail-limit=80",
BOOST_CHECK_EQUAL( config.get_config_file_name(), "conf/config_file.conf" );
BOOST_CHECK_EQUAL( config.get_source_network_interface(), "eth0" );
BOOST_CHECK_EQUAL( config.get_nameserver(), "localhost" );
+ BOOST_CHECK_EQUAL( config.get_netmark(), 42424242 );
BOOST_CHECK_EQUAL( config.get_hosts_down_limit(), 2 );
BOOST_CHECK_EQUAL( config.get_ping_fail_limit(), 80 );
BOOST_CHECK_EQUAL( config.get_status_notifier_cmd(), "scripts/notifier_command.sh" );
// if this assert fails, you must add or remove one of the options in the
// test below. Will probably find them all in
// src/config/configurationoptions.cpp constructor
- BOOST_CHECK_EQUAL( options.size(), 18 );
+ BOOST_CHECK_EQUAL( options.size(), 19 );
BOOST_CHECK_EQUAL( option_present( options, "hosts-down-limit" ), true );
BOOST_CHECK_EQUAL( option_present( options, "link-down-interval" ), true );
BOOST_CHECK_EQUAL( option_present( options, "nameserver" ), true );
BOOST_CHECK_EQUAL( option_present( options, "ping-fail-limit" ), true );
BOOST_CHECK_EQUAL( option_present( options, "default-source-network-interface" ), true );
+ BOOST_CHECK_EQUAL( option_present( options, "net-mark" ), true );
BOOST_CHECK_EQUAL( option_present( options, "status-notifier-cmd" ), true );
BOOST_CHECK_EQUAL( option_present( options, "ping-reply-timeout" ), true );
BOOST_CHECK_EQUAL( option_present( options, "max-address-resolution-attempts" ), true );
option_insert( "link-down-interval", boost::any( 30*60 ), vm );
option_insert( "link-up-interval", boost::any( 40*60 ), vm );
option_insert( "nameserver", boost::any( std::string("localhost") ), vm );
+ option_insert( "net-mark", boost::any( (unsigned int)42424242 ), vm );
option_insert( "ping-fail-limit", boost::any( 50 ), vm );
option_insert( "default-source-network-interface", boost::any( std::string("wlan1") ), vm );
option_insert( "status-notifier-cmd", boost::any( std::string("/tmp/command.sh") ), vm );
BOOST_CHECK_EQUAL( configuration.get_link_down_interval_in_sec(), 30*60 );
BOOST_CHECK_EQUAL( configuration.get_link_up_interval_in_sec(), 40*60 );
BOOST_CHECK_EQUAL( configuration.get_nameserver(), "localhost" );
+ BOOST_CHECK_EQUAL( configuration.get_netmark(), 42424242 );
BOOST_CHECK_EQUAL( configuration.get_ping_fail_limit(), 50 );
BOOST_CHECK_EQUAL( configuration.get_source_network_interface(), "wlan1" );
BOOST_CHECK_EQUAL( configuration.get_status_notifier_cmd(), "/tmp/command.sh" );