/*
 * rripmapper.{cc,hh} -- round robin IPMapper
 * Eddie Kohler
 *
 * Copyright (c) 2000 Massachusetts Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, subject to the conditions
 * listed in the Click LICENSE file. These conditions include: you must
 * preserve this copyright notice, and you cannot mention the copyright
 * holders in advertising related to the Software without their permission.
 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
 * notice is a summary of the Click LICENSE file; the license in that file is
 * legally binding.
 */

#include <click/config.h>
#include "rripmapper.hh"
#include <click/confparse.hh>
#include <click/error.hh>
CLICK_DECLS

RoundRobinIPMapper::RoundRobinIPMapper()
{
}

RoundRobinIPMapper::~RoundRobinIPMapper()
{
}

void *
RoundRobinIPMapper::cast(const char *name)
{
  if (name && strcmp("RoundRobinIPMapper", name) == 0)
    return (Element *)this;
  else if (name && strcmp("IPMapper", name) == 0)
    return (IPMapper *)this;
  else
    return 0;
}

int
RoundRobinIPMapper::configure(Vector<String> &conf, ErrorHandler *errh)
{
  if (conf.size() == 0)
    return errh->error("no patterns given");
  else if (conf.size() == 1)
    errh->warning("only one pattern given");

  int before = errh->nerrors();
  
  for (int i = 0; i < conf.size(); i++) {
    IPRw::Pattern *p;
    int f, r;
    if (IPRw::Pattern::parse_with_ports(conf[i], &p, &f, &r, this, errh) >= 0) {
      p->use();
      _patterns.push_back(p);
      _forward_outputs.push_back(f);
      _reverse_outputs.push_back(r);
    }
  }

  _last_pattern = 0;
  return (errh->nerrors() == before ? 0 : -1);
}

void
RoundRobinIPMapper::cleanup(CleanupStage)
{
  for (int i = 0; i < _patterns.size(); i++)
    _patterns[i]->unuse();
}

void
RoundRobinIPMapper::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 *
RoundRobinIPMapper::get_map(IPRw *rw, int ip_p, const IPFlowID &flow, Packet *)
{
  int first_pattern = _last_pattern;
  do {
    IPRw::Pattern *pat = _patterns[_last_pattern];
    int fport = _forward_outputs[_last_pattern];
    int rport = _reverse_outputs[_last_pattern];
    _last_pattern++;
    if (_last_pattern == _patterns.size())
      _last_pattern = 0;
    if (IPRw::Mapping *m = rw->apply_pattern(pat, ip_p, flow, fport, rport))
      return m;
  } while (_last_pattern != first_pattern);
  return 0;
}

CLICK_ENDDECLS
ELEMENT_REQUIRES(IPRw)
EXPORT_ELEMENT(RoundRobinIPMapper)


syntax highlighted by Code2HTML, v. 0.9.1