/*
* fastudpsourceip6.{cc,hh} -- fast udp source, a benchmark tool
*
* Copyright (c) 1999-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 <clicknet/ip6.h>
#include "fastudpsrcip6.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include <click/standard/alignmentinfo.hh>
#ifdef CLICK_LINUXMODULE
# include <net/checksum.h>
#endif
const unsigned FastUDPSourceIP6::NO_LIMIT;
FastUDPSourceIP6::FastUDPSourceIP6()
: _packet(0)
{
_rate_limited = true;
_first = _last = 0;
_count = 0;
}
FastUDPSourceIP6::~FastUDPSourceIP6()
{
}
int
FastUDPSourceIP6::configure(Vector<String> &conf, ErrorHandler *errh)
{
_cksum = true;
_active = true;
_interval = 0;
unsigned sp, dp;
unsigned rate;
int limit;
if (cp_va_parse(conf, this, errh,
cpUnsigned, "send rate", &rate,
cpInteger, "limit", &limit,
cpUnsigned, "packet length", &_len,
cpEthernetAddress, "src eth address", &_ethh.ether_shost,
cpIP6Address, "src ip6 address", &_sip6addr,
cpUnsigned, "src port", &sp,
cpEthernetAddress, "dst eth address", &_ethh.ether_dhost,
cpIP6Address, "dst ip6 address", &_dip6addr,
cpUnsigned, "dst port", &dp,
cpOptional,
cpBool, "do UDP checksum?", &_cksum,
cpUnsigned, "interval", &_interval,
cpBool, "active?", &_active,
cpEnd) < 0)
return -1;
if (sp >= 0x10000 || dp >= 0x10000)
return errh->error("source or destination port too large");
if (_len < 60) {
click_chatter("warning: packet length < 60, defaulting to 60");
_len = 60;
}
_ethh.ether_type = htons(0x86DD);
_sport = sp;
_dport = dp;
if(rate != 0){
_rate_limited = true;
_rate.set_rate(rate, errh);
} else {
_rate_limited = false;
}
_limit = (limit >= 0 ? limit : NO_LIMIT);
return 0;
}
void
FastUDPSourceIP6::incr_ports()
{
click_ip6 *ip6 = reinterpret_cast<click_ip6 *>(_packet->data()+14);
click_udp *udp = reinterpret_cast<click_udp *>(ip6 + 1);
_incr++;
udp->uh_sport = htons(_sport+_incr);
udp->uh_dport = htons(_dport+_incr);
udp->uh_sum = 0;
unsigned short len = _len-14-sizeof(click_ip6);
if (_cksum) {
//need to chagne
//unsigned csum = ~click_in_cksum((unsigned char *)udp, len) & 0xFFFF;
//udp->uh_sum = csum_tcpudp_magic(_sip6addr.s_addr, _dip6addr.s_addr,
// len, IP_PROTO_UDP, csum);
udp->uh_sum = htons(in6_fast_cksum(&ip6->ip6_src, &ip6->ip6_dst, ip6->ip6_plen, ip6->ip6_nxt, udp->uh_sum, (unsigned char *)udp, ip6->ip6_plen));
} else
udp->uh_sum = 0;
}
int
FastUDPSourceIP6::initialize(ErrorHandler *)
{
_count = 0;
_incr = 0;
_packet = Packet::make(_len);
memcpy(_packet->data(), &_ethh, 14);
click_ip6 *ip6 = reinterpret_cast<click_ip6 *>(_packet->data()+14);
click_udp *udp = reinterpret_cast<click_udp *>(ip6 + 1);
// set up IP6 header
ip6->ip6_flow = 0;
ip6->ip6_v = 6;
ip6->ip6_plen = htons(_len - 14 - sizeof(click_ip6));
ip6->ip6_nxt = IP_PROTO_UDP;
ip6->ip6_hlim = 250;
ip6->ip6_src = _sip6addr;
ip6->ip6_dst = _dip6addr;
_packet->set_dst_ip6_anno(IP6Address(_dip6addr));
_packet->set_ip6_header(ip6, sizeof(click_ip6));
// set up UDP header
udp->uh_sport = htons(_sport);
udp->uh_dport = htons(_dport);
udp->uh_sum = 0;
unsigned short len = _len-14-sizeof(click_ip6);
udp->uh_ulen = htons(len);
if (_cksum) {
//need to change, use our own checksum method
//unsigned csum = ~click_in_cksum((unsigned char *)udp, len) & 0xFFFF;
//udp->uh_sum = csum_tcpudp_magic(_sipaddr.s_addr, _dipaddr.s_addr,
// len, IP_PROTO_UDP, csum);
udp->uh_sum = htons(in6_fast_cksum(&ip6->ip6_src, &ip6->ip6_dst, ip6->ip6_plen, ip6->ip6_nxt, udp->uh_sum, (unsigned char *)udp, ip6->ip6_plen));
} else
udp->uh_sum = 0;
_skb = _packet->skb();
return 0;
}
void
FastUDPSourceIP6::cleanup(CleanupStage)
{
if (_packet) {
_packet->kill();
_packet=0;
}
}
Packet *
FastUDPSourceIP6::pull(int)
{
Packet *p = 0;
if (!_active || (_limit != NO_LIMIT && _count >= _limit)) return 0;
if(_rate_limited){
if (_rate.need_update(Timestamp::now())) {
_rate.update();
atomic_inc(&_skb->users);
p = reinterpret_cast<Packet *>(_skb);
}
} else {
atomic_inc(&_skb->users);
p = reinterpret_cast<Packet *>(_skb);
}
if(p) {
assert(atomic_read(&_skb->users) > 1);
_count++;
if(_count == 1)
_first = click_jiffies();
if(_limit != NO_LIMIT && _count >= _limit)
_last = click_jiffies();
if(_interval>0 && !(_count%_interval))
incr_ports();
}
return(p);
}
void
FastUDPSourceIP6::reset()
{
_count = 0;
_first = 0;
_last = 0;
_incr = 0;
}
static String
FastUDPSourceIP6_read_count_handler(Element *e, void *)
{
FastUDPSourceIP6 *c = (FastUDPSourceIP6 *)e;
return String(c->count());
}
static String
FastUDPSourceIP6_read_rate_handler(Element *e, void *)
{
FastUDPSourceIP6 *c = (FastUDPSourceIP6 *)e;
if(c->last() != 0){
int d = c->last() - c->first();
if (d < 1) d = 1;
int rate = c->count() * CLICK_HZ / d;
return String(rate);
} else {
return String("0");
}
}
static int
FastUDPSourceIP6_reset_write_handler
(const String &, Element *e, void *, ErrorHandler *)
{
FastUDPSourceIP6 *c = (FastUDPSourceIP6 *)e;
c->reset();
return 0;
}
static int
FastUDPSourceIP6_limit_write_handler
(const String &in_s, Element *e, void *, ErrorHandler *errh)
{
FastUDPSourceIP6 *c = (FastUDPSourceIP6 *)e;
String s = cp_uncomment(in_s);
unsigned limit;
if (!cp_unsigned(s, &limit))
return errh->error("limit parameter must be integer >= 0");
c->_limit = (limit >= 0 ? limit : c->NO_LIMIT);
return 0;
}
static int
FastUDPSourceIP6_rate_write_handler
(const String &in_s, Element *e, void *, ErrorHandler *errh)
{
FastUDPSourceIP6 *c = (FastUDPSourceIP6 *)e;
String s = cp_uncomment(in_s);
unsigned rate;
if (!cp_unsigned(s, &rate))
return errh->error("rate parameter must be integer >= 0");
if (rate > GapRate::MAX_RATE)
// report error rather than pin to max
return errh->error("rate too large; max is %u", GapRate::MAX_RATE);
c->_rate.set_rate(rate);
return 0;
}
static int
FastUDPSourceIP6_active_write_handler
(const String &in_s, Element *e, void *, ErrorHandler *errh)
{
FastUDPSourceIP6 *c = (FastUDPSourceIP6 *)e;
String s = cp_uncomment(in_s);
bool active;
if (!cp_bool(s, &active))
return errh->error("active parameter must be boolean");
c->_active = active;
if (active) c->reset();
return 0;
}
void
FastUDPSourceIP6::add_handlers()
{
add_read_handler("count", FastUDPSourceIP6_read_count_handler, 0);
add_read_handler("rate", FastUDPSourceIP6_read_rate_handler, 0);
add_write_handler("rate", FastUDPSourceIP6_rate_write_handler, 0);
add_write_handler("reset", FastUDPSourceIP6_reset_write_handler, 0);
add_write_handler("active", FastUDPSourceIP6_active_write_handler, 0);
add_write_handler("limit", FastUDPSourceIP6_limit_write_handler, 0);
}
ELEMENT_REQUIRES(linuxmodule ip6)
EXPORT_ELEMENT(FastUDPSourceIP6)
syntax highlighted by Code2HTML, v. 0.9.1