/*
* sourceipmapper.{cc,hh} -- source IP mapper (using consistent hashing)
*
* $Id: siphmapper.cc,v 1.7 2005/09/19 22:39:39 eddietwo Exp $
*
*/
#include <click/config.h>
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#if CLICK_BSDMODULE
# include <machine/limits.h>
#endif
#include "siphmapper.hh"
CLICK_DECLS
SourceIPHashMapper::SourceIPHashMapper()
: _hasher (NULL)
{
}
SourceIPHashMapper::~SourceIPHashMapper()
{
}
void *
SourceIPHashMapper::cast(const char *name)
{
if (name && strcmp("SourceIPHashMapper", name) == 0)
return (Element *)this;
else if (name && strcmp("IPMapper", name) == 0)
return (IPMapper *)this;
else
return 0;
}
int
SourceIPHashMapper::parse_server (const String &conf, IPRw::Pattern **pstore,
int *fport_store, int *rport_store,
int *id_store, Element *e,
ErrorHandler *errh)
{
Vector<String> words;
cp_spacevec(conf, words);
int32_t id;
if (words.size () <= 1
|| !cp_integer(words[words.size() - 1], &id)
|| id < 0)
return errh->error("bad server ID in pattern spec");
words.resize(words.size() - 1);
*id_store = id;
return IPRw::Pattern::parse_with_ports (cp_unspacevec(words), pstore,
fport_store,
rport_store, e, errh);
}
int
SourceIPHashMapper::configure(Vector<String> &conf, ErrorHandler *errh)
{
if (conf.size () == 0)
return errh->error ("no hash seed given");
else if (conf.size() == 1)
return errh->error("no patterns given");
else if (conf.size() == 2)
errh->warning("only one pattern given");
int before = errh->nerrors();
int nnodes;
int32_t seed;
Vector<String> params;
cp_spacevec (conf[0], params);
if (params.size () != 2)
return errh->error("requires 2 config params: numnodes seed");
if (!cp_integer(params[0], &nnodes) || nnodes <= 0)
return errh->error("number of nodes must be an integer");
if (!cp_integer(params[1], &seed))
return errh->error("hash seed must be an integer");
int idp = 0;
unsigned short *ids = new unsigned short[conf.size ()];
for (int i = 1; i < conf.size(); i++) {
IPRw::Pattern *p;
int f, r, id;
if (parse_server (conf[i], &p, &f, &r, &id, this, errh) >= 0) {
p->use();
_patterns.push_back(p);
_forward_outputs.push_back(f);
_reverse_outputs.push_back(r);
ids[idp++] = id;
}
}
if (_hasher)
delete (_hasher);
_hasher = new chash_t<int> (idp, ids, nnodes, seed);
delete [] ids;
return (errh->nerrors() == before ? 0 : -1);
}
void
SourceIPHashMapper::cleanup(CleanupStage)
{
for (int i = 0; i < _patterns.size(); i++)
_patterns[i]->unuse();
delete _hasher;
}
void
SourceIPHashMapper::notify_rewriter(IPRw *rw, ErrorHandler *errh)
{
int no = rw->noutputs();
for (int i = 0; i < _patterns.size(); i++) {
if (_forward_outputs[i] >= no || _reverse_outputs[i] >= no)
errh->error("port in `%s' out of range for `%s'", declaration().c_str(), rw->declaration().c_str());
rw->notify_pattern(_patterns[i], errh);
}
}
IPRw::Mapping *
SourceIPHashMapper::get_map(IPRw *rw, int ip_p, const IPFlowID &flow,
Packet *p)
{
const click_ip *iph = p->ip_header();
const struct in_addr ipsrc = iph->ip_src;
unsigned int tmp, t2;
memcpy (&tmp, &ipsrc, sizeof (tmp));
t2 = tmp & 0xff;
// make the lower bits have some more impact so that adjacent
// IPs can be hashed to different servers.
// note that this really isn't necessary for i386 alignment...
tmp *= ((t2 << 24) | 0x1);
tmp = tmp % INT_MAX;
int v = _hasher->hash2ind (tmp);
IPRw::Pattern *pat = _patterns[v];
int fport = _forward_outputs[v];
int rport = _reverse_outputs[v];
// debug code
click_chatter ("%p -> %d", (void *)tmp, v);
return (rw->apply_pattern(pat, ip_p, flow, fport, rport));
}
CLICK_ENDDECLS
ELEMENT_REQUIRES(IPRw)
EXPORT_ELEMENT(SourceIPHashMapper)
syntax highlighted by Code2HTML, v. 0.9.1