summaryrefslogtreecommitdiff
path: root/src/lbpathtest.cc
diff options
context:
space:
mode:
authorslioch <slioch@eng-140.vyatta.com>2009-07-17 15:06:04 -0700
committerslioch <slioch@eng-140.vyatta.com>2009-07-17 15:06:04 -0700
commit25d9851b65fed9297caaa01b47ec6bae76d8c954 (patch)
treef408dedd6fddd8cc156002f56f0618b5b0efa261 /src/lbpathtest.cc
parentc1e5c748aac314a2f0652393fbb9f8c079055106 (diff)
downloadvyatta-wanloadbalance-25d9851b65fed9297caaa01b47ec6bae76d8c954.tar.gz
vyatta-wanloadbalance-25d9851b65fed9297caaa01b47ec6bae76d8c954.zip
reworked target code to support multiple targets and different target types.
user can now specify a sequence of targets to test (ordered by rule number). The first success satifies the success criteria for the test and no further tests will be performed on the interface for this period. Additional test types can be coded and added to the target framework. configuration has changed as a result of the rework.
Diffstat (limited to 'src/lbpathtest.cc')
-rw-r--r--src/lbpathtest.cc322
1 files changed, 37 insertions, 285 deletions
diff --git a/src/lbpathtest.cc b/src/lbpathtest.cc
index d7ed6cd..7fd45a5 100644
--- a/src/lbpathtest.cc
+++ b/src/lbpathtest.cc
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <iostream>
#include <string>
+#include <vector>
#include <algorithm>
#include "lbdata.hh"
@@ -31,318 +32,69 @@
using namespace std;
+/**
+ *
+ *
+ **/
LBPathTest::LBPathTest(bool debug) :
- _debug(debug),
- _send_sock(0),
- _recv_sock(0),
- _packet_id(0)
+ _debug(debug)
{
- struct protoent *ppe = getprotobyname("icmp");
- _send_sock = socket(PF_INET, SOCK_RAW, ppe->p_proto);
- if (_send_sock < 0){
- if (_debug) {
- cerr << "LBPathTest::LBPathTest(): no send sock: " << _send_sock << endl;
- }
- syslog(LOG_ERR, "wan_lb: failed to acquired socket");
- _send_sock = 0;
- return;
- }
-
- //set options for broadcasting.
- int val = 1;
- setsockopt(_send_sock, SOL_SOCKET, SO_BROADCAST, &val, 4);
- setsockopt(_send_sock, SOL_SOCKET, SO_REUSEADDR, &val, 4);
-
- struct sockaddr_in addr;
- memset( &addr, 0, sizeof( struct sockaddr_in ));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = 0;
-
- _recv_sock = socket(PF_INET, SOCK_RAW, ppe->p_proto);
- if (_recv_sock < 0) {
- if (_debug) {
- cerr << "LBPathTest::LBPathTest(): no recv sock: " << _recv_sock << endl;
- }
- syslog(LOG_ERR, "wan_lb: failed to acquired socket");
- _recv_sock = 0;
- return;
- }
- if (bind(_recv_sock, (struct sockaddr*)&addr, sizeof(addr))==-1) {
- if (_debug) {
- cerr << "failed on bind" << endl;
- }
- syslog(LOG_ERR, "wan_lb: failed to bind recv sock");
- }
}
+/**
+ *
+ *
+ **/
LBPathTest::~LBPathTest()
{
- if (_recv_sock)
- close(_recv_sock);
-
- if (_send_sock)
- close(_send_sock);
}
+/**
+ *
+ *
+ **/
void
LBPathTest::start(LBData &lb_data)
{
+ //iterate through the tests until success per interface or complete
if (_debug) {
- cout << "LBPathTest::start(): starting health test. client ct: " << lb_data._iface_health_coll.size() << endl;
+ cout << "LBPathTest::start(): init" << endl;
}
- map<int,PktData> results;
-
- struct timeval send_time;
- gettimeofday(&send_time,NULL);
+ set<LBHealth*> coll;
- int ct = 0;
- //iterate over packets and send
LBData::InterfaceHealthIter iter = lb_data._iface_health_coll.begin();
while (iter != lb_data._iface_health_coll.end()) {
- string target = iter->second._ping_target;
- if (target.empty()) {
- if (iter->second._nexthop == "dhcp") {
- target = iter->second._dhcp_nexthop;
- }
- else {
- target = iter->second._nexthop;
- }
- }
-
- //don't have target yet...
- if (target.empty()) {
- return;
- }
- if (_debug) {
- cout << "LBPathTest::start(): sending ping test for: " << iter->first << " for " << target << endl;
- }
- _packet_id = ++_packet_id % 32767;
- send(iter->first, target, _packet_id);
- results.insert(pair<int,PktData>(_packet_id,PktData(iter->first,-1)));
+ iter->second.start_new_test_cycle();
+ coll.insert(&(iter->second));
- ++ct;
++iter;
}
-
- //use gettimeofday to calculate time to millisecond
-
- //use sysinfo to make sure we don't get stuck in a loop with timechange
- struct sysinfo si;
- sysinfo(&si);
- //for now hardcode to 5 second overall timeout
- int timeout = si.uptime + 5; //seconds
- int cur_time = si.uptime;
-
- //then iterate over recv socket and receive and record
- while (ct > 0 && cur_time < timeout) {
- int id = receive();
- if (_debug) {
- cout << "LBPathTest::start(): " << id << endl;
- }
- //update current time for comparison
- sysinfo(&si);
- timeval recv_time;
- gettimeofday(&recv_time,NULL);
- cur_time = si.uptime;
- map<int,PktData>::iterator r_iter = results.find(id);
- if (r_iter != results.end()) {
-
- //calculate time in milliseconds
- int secs = 0;
- int msecs = recv_time.tv_usec - send_time.tv_usec;
- if (msecs < 0) {
- secs = recv_time.tv_sec - send_time.tv_sec - 1;
- }
- else {
- secs = recv_time.tv_sec - send_time.tv_sec;
- }
- //time in milliseconds below
- int rtt = abs(msecs) / 1000 + 1000 * secs;
-
- LBData::InterfaceHealthIter iter = lb_data._iface_health_coll.find(r_iter->second._iface);
- if (iter != lb_data._iface_health_coll.end()) {
- //check to see if this returned in the configured time, otherwise apply timeout
- if (_debug) {
- cout << "LBPathTest::start(): received pkt: " << iter->first << ", rtt: " << rtt << endl;
- }
- if (rtt < iter->second._ping_resp_time) {
- iter->second.put(rtt);
- }
- else {
- iter->second.put(-1);
- }
- }
- results.erase(r_iter);
- --ct;
- }
- }
- //we're done waiting, mark the rest as non-responsive
- map<int,PktData>::iterator r_iter = results.begin();
- while (r_iter != results.end()) {
- LBData::InterfaceHealthIter iter = lb_data._iface_health_coll.find(r_iter->second._iface);
- if (iter != lb_data._iface_health_coll.end()) {
- iter->second.put(-1);
- }
- ++r_iter;
- }
-
- if (_debug) {
- cout << "LBPathTest::start(): finished heath test" << endl;
- }
-}
-
-void
-LBPathTest::send(const string &iface, const string &target_addr, int packet_id)
-{
- int err;
- sockaddr_in taddr;
- timeval send_time;
- icmphdr *icmp_hdr;
- int icmp_pktsize = 40;
- char buffer[icmp_pktsize];
-
- if (iface.empty() || target_addr.empty()) {
- return;
- }
-
- // bind a socket to a device name (might not work on all systems):
- if (setsockopt(_send_sock, SOL_SOCKET, SO_BINDTODEVICE, iface.c_str(), iface.size()) != 0) {
- syslog(LOG_ERR, "wan_lb: failure to bind to interface: %s", iface.c_str());
- return; //will allow the test to time out then
- }
-
- //convert target_addr to ip addr
- struct hostent *h = gethostbyname(target_addr.c_str());
- if (h == NULL) {
+ while (!coll.empty()) {
if (_debug) {
- cerr << "LBPathTest::send() Error in resolving hostname" << endl;
+ cout << "LBPathTest::start(): sending " << coll.size() << " tests" << endl;
}
- syslog(LOG_ERR, "wan_lb: error in resolving configured hostname: %s", target_addr.c_str());
- return;
- }
-
- icmp_hdr = (struct icmphdr *)buffer;
- icmp_hdr->type = ICMP_ECHO;
- icmp_hdr->code = 0;
- icmp_hdr->checksum = 0;
- icmp_hdr->un.echo.id = htons(getpid());
- icmp_hdr->un.echo.sequence = 0;
- int length = sizeof(buffer);
-
- //we'll put in time of packet sent for the heck of it, may
- //want to use this in future tests, feel free to remove.
- gettimeofday(&send_time, (struct timezone*)NULL);
- char* datap = &buffer[8];
- memcpy(datap, (char*)&send_time.tv_sec, sizeof(send_time.tv_sec));
- datap = &buffer[12];
- memcpy(datap, (char*)&send_time.tv_usec, sizeof(send_time.tv_usec));
- datap = &buffer[16];
- memcpy(datap, (char*)&packet_id, sizeof(packet_id)); //packet id
- datap = &buffer[18];
- int val(icmp_pktsize);
- memcpy(datap, (char*)&val, 2); //packet id
-
- icmp_hdr->un.echo.sequence = 1;
- icmp_hdr->checksum = 0;
- icmp_hdr->checksum = in_checksum((unsigned short *)icmp_hdr,length>>1);
-
- struct in_addr ia;
- memcpy(&ia, h->h_addr_list[0], sizeof(ia));
- unsigned long addr = ia.s_addr;
-
- taddr.sin_addr.s_addr = addr;
- taddr.sin_family = AF_INET;
- bzero(&(taddr.sin_zero), 8);
-
- //need to direct this packet out a specific interface!!!!!!!!!!!!!
- err = sendto(_send_sock, buffer, icmp_pktsize, 0, (struct sockaddr*)&taddr, sizeof(taddr));
- if (_debug) {
- cout << "lbpathtest: sendto: " << err << ", packet id: " << packet_id << endl;
- }
- if(err < 0)
- {
+ //send all interface tests together
+ set<LBHealth*>::iterator i = coll.begin();
+ while (i != coll.end()) {
+ (*i)->send_test();
+ ++i;
+ }
+
if (_debug) {
- if (errno == EBADF)
- cout << "EBADF" << endl;
- else if (errno == ENOTSOCK)
- cout << "ENOTSOCK" << endl;
- else if (errno == EFAULT)
- cout << "EFAULT" << endl;
- else if (errno == EMSGSIZE)
- cout << "EMSGSIZE" << endl;
- else if (errno == EWOULDBLOCK)
- cout << "EWOULDBLOCK" << endl;
- else if (errno == EAGAIN)
- cout << "EAGAIN" << endl;
- else if (errno == ENOBUFS)
- cout << "ENOBUFS" << endl;
- else if (errno == EINTR)
- cout << "EINTR" << endl;
- else if (errno == ENOMEM)
- cout << "ENOMEM" << endl;
- else if (errno == EACCES)
- cout << "EACCES" << endl;
- else if (errno == EINVAL)
- cout << "EINVAL" << endl;
- else if (errno == EPIPE)
- cout << "EPIPE" << endl;
- else
- cout << "unknown error: " << errno << endl;
+ cout << "LBPathTest::start(): waiting on recv" << endl;
}
- syslog(LOG_ERR, "wan_lb: error on sending icmp packet: %d", errno);
- }
-}
-
-int
-LBPathTest::receive()
-{
- int icmp_pktsize = 40;
- char resp_buf[icmp_pktsize];
- icmphdr *icmp_hdr;
- timeval wait_time;
- fd_set readfs;
- int ret;
-
- FD_ZERO(&readfs);
- FD_SET(_recv_sock, &readfs);
-
- wait_time.tv_usec = 0;
- wait_time.tv_sec = 3; //3 second timeout
-
- while (select(_recv_sock+1, &readfs, NULL, NULL, &wait_time) != 0)
- {
- ret = recv(_recv_sock, &resp_buf, icmp_pktsize, 0);
- if (ret != -1)
- {
- icmp_hdr = (struct icmphdr *)(resp_buf + sizeof(iphdr));
- if (icmp_hdr->type == ICMP_ECHOREPLY)
- {
- if (_debug) {
- cout << "LBPathTest::receive(): " << endl;
- }
- //process packet data
- char* data;
- int id = 0;
- data = (char*)(&resp_buf) + 36;
- memcpy(&id, data, sizeof(unsigned short));
- return id;
+ //wait on responses
+ i = coll.begin();
+ while (i != coll.end()) {
+ if ((*i)->recv_test()) {
+ coll.erase(i++);
+ }
+ else {
+ ++i;
}
}
}
- return -1;
-}
-
-unsigned short
-LBPathTest::in_checksum(const unsigned short *buffer, int length) const
-{
- unsigned long sum;
- for (sum=0; length>0; length--)
- sum += *buffer++;
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
- return ~sum;
}